# HG changeset patch # User duke # Date 1499267892 -7200 # Node ID 88db80c8e49cea352c2900f689600dc410761c1f # Parent 2f471c697ba267e8684068dc1cdb66be02554aee# Parent c4a3e3140f7bd13c8695bf616c19f6cfafc76732 Merge diff -r c4a3e3140f7b -r 88db80c8e49c .hgtags-top-repo --- a/.hgtags-top-repo Wed Jul 05 17:17:22 2017 +0200 +++ b/.hgtags-top-repo Wed Jul 05 17:18:12 2017 +0200 @@ -75,3 +75,4 @@ 6cea9984d73d74de0cd01f30d07ac0a1ed196117 jdk7-b98 e7f18db469a3e947b7096bfd12e87380e5a042cd jdk7-b99 b218a53ec7d3d42be61d31d6917a6c5c037b6f56 jdk7-b100 +4193eaf5f1b82794c6a0fb1a8d11af43d1b1d611 jdk7-b101 diff -r c4a3e3140f7b -r 88db80c8e49c corba/.hgtags --- a/corba/.hgtags Wed Jul 05 17:17:22 2017 +0200 +++ b/corba/.hgtags Wed Jul 05 17:18:12 2017 +0200 @@ -75,3 +75,4 @@ 3b99409057e4c255da946f9f540d051a5ef4ab23 jdk7-b98 95db968660e7d87c345d5cf3dc2e3db037fb7220 jdk7-b99 a56d734a1e970e1a21a8f4feb13053e9a33674c7 jdk7-b100 +86a239832646a74811695428984b6947c0bd6dc8 jdk7-b101 diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/.hgtags --- a/hotspot/.hgtags Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/.hgtags Wed Jul 05 17:18:12 2017 +0200 @@ -104,3 +104,5 @@ 8a045b3f5c13eaad92ff4baf15ca671845fcad1a jdk7-b98 6a236384a379642b5a2398e2819db9ab4e711e9b jdk7-b99 ad1977f08c4d69162a0775fe3f9576b9fd521d10 jdk7-b100 +6c3a919105b68c15b7db923ec9a00006e9560910 jdk7-b101 +ad1977f08c4d69162a0775fe3f9576b9fd521d10 hs19-b03 diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Wed Jul 05 17:18:12 2017 +0200 @@ -35,7 +35,6 @@ public class NMethod extends CodeBlob { private static long pcDescSize; - private static CIntegerField zombieInstructionSizeField; private static sun.jvm.hotspot.types.OopField methodField; /** != InvocationEntryBci if this nmethod is an on-stack replacement method */ private static CIntegerField entryBCIField; @@ -88,7 +87,6 @@ private static void initialize(TypeDataBase db) { Type type = db.lookupType("nmethod"); - zombieInstructionSizeField = type.getCIntegerField("_zombie_instruction_size"); methodField = type.getOopField("_method"); entryBCIField = type.getCIntegerField("_entry_bci"); osrLinkField = type.getAddressField("_osr_link"); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeDisassembler.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeDisassembler.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeDisassembler.java Wed Jul 05 17:18:12 2017 +0200 @@ -72,6 +72,7 @@ addBytecodeClass(Bytecodes._invokestatic, BytecodeInvoke.class); addBytecodeClass(Bytecodes._invokespecial, BytecodeInvoke.class); addBytecodeClass(Bytecodes._invokeinterface, BytecodeInvoke.class); + addBytecodeClass(Bytecodes._invokedynamic, BytecodeInvoke.class); addBytecodeClass(Bytecodes._jsr, BytecodeJsr.class); addBytecodeClass(Bytecodes._jsr_w, BytecodeJsrW.class); addBytecodeClass(Bytecodes._iload, BytecodeLoad.class); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeInvoke.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeInvoke.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeInvoke.java Wed Jul 05 17:18:12 2017 +0200 @@ -54,15 +54,31 @@ // returns the name of the invoked method public Symbol name() { ConstantPool cp = method().getConstants(); + if (isInvokedynamic()) { + int[] nt = cp.getNameAndTypeAt(indexForFieldOrMethod()); + return cp.getSymbolAt(nt[0]); + } return cp.getNameRefAt(index()); } // returns the signature of the invoked method public Symbol signature() { ConstantPool cp = method().getConstants(); + if (isInvokedynamic()) { + int[] nt = cp.getNameAndTypeAt(indexForFieldOrMethod()); + return cp.getSymbolAt(nt[1]); + } return cp.getSignatureRefAt(index()); } + public int getSecondaryIndex() { + if (isInvokedynamic()) { + // change byte-ordering of 4-byte integer + return VM.getVM().getBytes().swapInt(javaSignedWordAt(1)); + } + return super.getSecondaryIndex(); // throw an error + } + public Method getInvokedMethod() { return method().getConstants().getMethodRefAt(index()); } @@ -87,6 +103,7 @@ public boolean isInvokevirtual() { return adjustedInvokeCode() == Bytecodes._invokevirtual; } public boolean isInvokestatic() { return adjustedInvokeCode() == Bytecodes._invokestatic; } public boolean isInvokespecial() { return adjustedInvokeCode() == Bytecodes._invokespecial; } + public boolean isInvokedynamic() { return adjustedInvokeCode() == Bytecodes._invokedynamic; } public boolean isValid() { return isInvokeinterface() || isInvokevirtual() || @@ -104,6 +121,11 @@ buf.append(spaces); buf.append('#'); buf.append(Integer.toString(indexForFieldOrMethod())); + if (isInvokedynamic()) { + buf.append('('); + buf.append(Integer.toString(getSecondaryIndex())); + buf.append(')'); + } buf.append(" [Method "); StringBuffer sigBuf = new StringBuffer(); new SignatureConverter(signature(), sigBuf).iterateReturntype(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Wed Jul 05 17:18:12 2017 +0200 @@ -25,6 +25,7 @@ package sun.jvm.hotspot.interpreter; import sun.jvm.hotspot.oops.*; +import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.utilities.*; public class BytecodeLoadConstant extends BytecodeWithCPIndex { @@ -32,10 +33,47 @@ super(method, bci); } + public boolean hasCacheIndex() { + // normal ldc uses CP index, but fast_aldc uses swapped CP cache index + return javaCode() != code(); + } + public int index() { - return javaCode() == Bytecodes._ldc ? + int i = javaCode() == Bytecodes._ldc ? (int) (0xFF & javaByteAt(1)) : (int) (0xFFFF & javaShortAt(1)); + if (hasCacheIndex()) { + return (0xFFFF & VM.getVM().getBytes().swapShort((short) i)); + } else { + return i; + } + } + + public int poolIndex() { + int i = index(); + if (hasCacheIndex()) { + ConstantPoolCache cpCache = method().getConstants().getCache(); + return cpCache.getEntryAt(i).getConstantPoolIndex(); + } else { + return i; + } + } + + public int cacheIndex() { + if (hasCacheIndex()) { + return index(); + } else { + return -1; // no cache index + } + } + + private Oop getCachedConstant() { + int i = cacheIndex(); + if (i >= 0) { + ConstantPoolCache cpCache = method().getConstants().getCache(); + return cpCache.getEntryAt(i).getF1(); + } + return null; } public void verify() { @@ -58,6 +96,7 @@ // has to be int or float or String or Klass return (ctag.isUnresolvedString() || ctag.isString() || ctag.isUnresolvedKlass() || ctag.isKlass() + || ctag.isMethodHandle() || ctag.isMethodType() || ctag.isInt() || ctag.isFloat())? true: false; } } @@ -112,7 +151,7 @@ public String getConstantValue() { ConstantPool cpool = method().getConstants(); - int cpIndex = index(); + int cpIndex = poolIndex(); ConstantTag ctag = cpool.getTagAt(cpIndex); if (ctag.isInt()) { return ""; @@ -149,6 +188,18 @@ } else { throw new RuntimeException("should not reach here"); } + } else if (ctag.isMethodHandle() || ctag.isMethodType()) { + Oop x = getCachedConstant(); + int refidx = cpool.getMethodHandleIndexAt(cpIndex); + int refkind = cpool.getMethodHandleRefKindAt(cpIndex); + return ""; + } else if (ctag.isMethodType()) { + Oop x = getCachedConstant(); + int refidx = cpool.getMethodTypeIndexAt(cpIndex); + return ""; } else { if (Assert.ASSERTS_ENABLED) { Assert.that(false, "invalid load constant type"); @@ -162,7 +213,12 @@ buf.append(getJavaBytecodeName()); buf.append(spaces); buf.append('#'); - buf.append(Integer.toString(index())); + buf.append(Integer.toString(poolIndex())); + if (hasCacheIndex()) { + buf.append('('); + buf.append(Integer.toString(cacheIndex())); + buf.append(')'); + } buf.append(spaces); buf.append(getConstantValue()); if (code() != javaCode()) { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithCPIndex.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithCPIndex.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithCPIndex.java Wed Jul 05 17:18:12 2017 +0200 @@ -37,12 +37,19 @@ // the constant pool index for this bytecode public int index() { return 0xFFFF & javaShortAt(1); } + public int getSecondaryIndex() { + throw new IllegalArgumentException("must be invokedynamic"); + } + protected int indexForFieldOrMethod() { ConstantPoolCache cpCache = method().getConstants().getCache(); // get ConstantPool index from ConstantPoolCacheIndex at given bci int cpCacheIndex = index(); if (cpCache == null) { return cpCacheIndex; + } else if (code() == Bytecodes._invokedynamic) { + int secondaryIndex = getSecondaryIndex(); + return cpCache.getMainEntryAt(secondaryIndex).getConstantPoolIndex(); } else { // change byte-ordering and go via cache return cpCache.getEntryAt((int) (0xFFFF & VM.getVM().getBytes().swapShort((short) cpCacheIndex))).getConstantPoolIndex(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java Wed Jul 05 17:18:12 2017 +0200 @@ -222,7 +222,7 @@ public static final int _invokespecial = 183; // 0xb7 public static final int _invokestatic = 184; // 0xb8 public static final int _invokeinterface = 185; // 0xb9 - public static final int _xxxunusedxxx = 186; // 0xba + public static final int _invokedynamic = 186; // 0xba public static final int _new = 187; // 0xbb public static final int _newarray = 188; // 0xbc public static final int _anewarray = 189; // 0xbd @@ -269,9 +269,12 @@ public static final int _fast_invokevfinal = 226; public static final int _fast_linearswitch = 227; public static final int _fast_binaryswitch = 228; - public static final int _shouldnotreachhere = 229; // For debugging + public static final int _fast_aldc = 229; + public static final int _fast_aldc_w = 230; + public static final int _return_register_finalizer = 231; + public static final int _shouldnotreachhere = 232; // For debugging - public static final int number_of_codes = 230; + public static final int number_of_codes = 233; public static int specialLengthAt(Method method, int bci) { int code = codeAt(method, bci); @@ -458,9 +461,9 @@ def(_dconst_1 , "dconst_1" , "b" , null , BasicType.getTDouble() , 2, false); def(_bipush , "bipush" , "bc" , null , BasicType.getTInt() , 1, false); def(_sipush , "sipush" , "bcc" , null , BasicType.getTInt() , 1, false); - def(_ldc , "ldc" , "bi" , null , BasicType.getTIllegal(), 1, true ); - def(_ldc_w , "ldc_w" , "bii" , null , BasicType.getTIllegal(), 1, true ); - def(_ldc2_w , "ldc2_w" , "bii" , null , BasicType.getTIllegal(), 2, true ); + def(_ldc , "ldc" , "bk" , null , BasicType.getTIllegal(), 1, true ); + def(_ldc_w , "ldc_w" , "bkk" , null , BasicType.getTIllegal(), 1, true ); + def(_ldc2_w , "ldc2_w" , "bkk" , null , BasicType.getTIllegal(), 2, true ); def(_iload , "iload" , "bi" , "wbii" , BasicType.getTInt() , 1, false); def(_lload , "lload" , "bi" , "wbii" , BasicType.getTLong() , 2, false); def(_fload , "fload" , "bi" , "wbii" , BasicType.getTFloat() , 1, false); @@ -618,26 +621,26 @@ def(_dreturn , "dreturn" , "b" , null , BasicType.getTDouble() , -2, true ); def(_areturn , "areturn" , "b" , null , BasicType.getTObject() , -1, true ); def(_return , "return" , "b" , null , BasicType.getTVoid() , 0, true ); - def(_getstatic , "getstatic" , "bjj" , null , BasicType.getTIllegal(), 1, true ); - def(_putstatic , "putstatic" , "bjj" , null , BasicType.getTIllegal(), -1, true ); - def(_getfield , "getfield" , "bjj" , null , BasicType.getTIllegal(), 0, true ); - def(_putfield , "putfield" , "bjj" , null , BasicType.getTIllegal(), -2, true ); - def(_invokevirtual , "invokevirtual" , "bjj" , null , BasicType.getTIllegal(), -1, true ); - def(_invokespecial , "invokespecial" , "bjj" , null , BasicType.getTIllegal(), -1, true ); - def(_invokestatic , "invokestatic" , "bjj" , null , BasicType.getTIllegal(), 0, true ); - def(_invokeinterface , "invokeinterface" , "bjj__", null , BasicType.getTIllegal(), -1, true ); - def(_xxxunusedxxx , "xxxunusedxxx" , null , null , BasicType.getTVoid() , 0, false); - def(_new , "new" , "bii" , null , BasicType.getTObject() , 1, true ); + def(_getstatic , "getstatic" , "bJJ" , null , BasicType.getTIllegal(), 1, true ); + def(_putstatic , "putstatic" , "bJJ" , null , BasicType.getTIllegal(), -1, true ); + def(_getfield , "getfield" , "bJJ" , null , BasicType.getTIllegal(), 0, true ); + def(_putfield , "putfield" , "bJJ" , null , BasicType.getTIllegal(), -2, true ); + def(_invokevirtual , "invokevirtual" , "bJJ" , null , BasicType.getTIllegal(), -1, true ); + def(_invokespecial , "invokespecial" , "bJJ" , null , BasicType.getTIllegal(), -1, true ); + def(_invokestatic , "invokestatic" , "bJJ" , null , BasicType.getTIllegal(), 0, true ); + def(_invokeinterface , "invokeinterface" , "bJJ__", null , BasicType.getTIllegal(), -1, true ); + def(_invokedynamic , "invokedynamic" , "bJJJJ", null , BasicType.getTIllegal(), -1, true ); + def(_new , "new" , "bkk" , null , BasicType.getTObject() , 1, true ); def(_newarray , "newarray" , "bc" , null , BasicType.getTObject() , 0, true ); - def(_anewarray , "anewarray" , "bii" , null , BasicType.getTObject() , 0, true ); + def(_anewarray , "anewarray" , "bkk" , null , BasicType.getTObject() , 0, true ); def(_arraylength , "arraylength" , "b" , null , BasicType.getTVoid() , 0, true ); def(_athrow , "athrow" , "b" , null , BasicType.getTVoid() , -1, true ); - def(_checkcast , "checkcast" , "bii" , null , BasicType.getTObject() , 0, true ); - def(_instanceof , "instanceof" , "bii" , null , BasicType.getTInt() , 0, true ); + def(_checkcast , "checkcast" , "bkk" , null , BasicType.getTObject() , 0, true ); + def(_instanceof , "instanceof" , "bkk" , null , BasicType.getTInt() , 0, true ); def(_monitorenter , "monitorenter" , "b" , null , BasicType.getTVoid() , -1, true ); def(_monitorexit , "monitorexit" , "b" , null , BasicType.getTVoid() , -1, true ); def(_wide , "wide" , "" , null , BasicType.getTVoid() , 0, false); - def(_multianewarray , "multianewarray" , "biic" , null , BasicType.getTObject() , 1, true ); + def(_multianewarray , "multianewarray" , "bkkc" , null , BasicType.getTObject() , 1, true ); def(_ifnull , "ifnull" , "boo" , null , BasicType.getTVoid() , -1, false); def(_ifnonnull , "ifnonnull" , "boo" , null , BasicType.getTVoid() , -1, false); def(_goto_w , "goto_w" , "boooo", null , BasicType.getTVoid() , 0, false); @@ -646,38 +649,44 @@ // JVM bytecodes // bytecode bytecode name format wide f. result tp stk traps std code - def(_fast_agetfield , "fast_agetfield" , "bjj" , null , BasicType.getTObject() , 0, true , _getfield ); - def(_fast_bgetfield , "fast_bgetfield" , "bjj" , null , BasicType.getTInt() , 0, true , _getfield ); - def(_fast_cgetfield , "fast_cgetfield" , "bjj" , null , BasicType.getTChar() , 0, true , _getfield ); - def(_fast_dgetfield , "fast_dgetfield" , "bjj" , null , BasicType.getTDouble() , 0, true , _getfield ); - def(_fast_fgetfield , "fast_fgetfield" , "bjj" , null , BasicType.getTFloat() , 0, true , _getfield ); - def(_fast_igetfield , "fast_igetfield" , "bjj" , null , BasicType.getTInt() , 0, true , _getfield ); - def(_fast_lgetfield , "fast_lgetfield" , "bjj" , null , BasicType.getTLong() , 0, true , _getfield ); - def(_fast_sgetfield , "fast_sgetfield" , "bjj" , null , BasicType.getTShort() , 0, true , _getfield ); + def(_fast_agetfield , "fast_agetfield" , "bJJ" , null , BasicType.getTObject() , 0, true , _getfield ); + def(_fast_bgetfield , "fast_bgetfield" , "bJJ" , null , BasicType.getTInt() , 0, true , _getfield ); + def(_fast_cgetfield , "fast_cgetfield" , "bJJ" , null , BasicType.getTChar() , 0, true , _getfield ); + def(_fast_dgetfield , "fast_dgetfield" , "bJJ" , null , BasicType.getTDouble() , 0, true , _getfield ); + def(_fast_fgetfield , "fast_fgetfield" , "bJJ" , null , BasicType.getTFloat() , 0, true , _getfield ); + def(_fast_igetfield , "fast_igetfield" , "bJJ" , null , BasicType.getTInt() , 0, true , _getfield ); + def(_fast_lgetfield , "fast_lgetfield" , "bJJ" , null , BasicType.getTLong() , 0, true , _getfield ); + def(_fast_sgetfield , "fast_sgetfield" , "bJJ" , null , BasicType.getTShort() , 0, true , _getfield ); - def(_fast_aputfield , "fast_aputfield" , "bjj" , null , BasicType.getTObject() , 0, true , _putfield ); - def(_fast_bputfield , "fast_bputfield" , "bjj" , null , BasicType.getTInt() , 0, true , _putfield ); - def(_fast_cputfield , "fast_cputfield" , "bjj" , null , BasicType.getTChar() , 0, true , _putfield ); - def(_fast_dputfield , "fast_dputfield" , "bjj" , null , BasicType.getTDouble() , 0, true , _putfield ); - def(_fast_fputfield , "fast_fputfield" , "bjj" , null , BasicType.getTFloat() , 0, true , _putfield ); - def(_fast_iputfield , "fast_iputfield" , "bjj" , null , BasicType.getTInt() , 0, true , _putfield ); - def(_fast_lputfield , "fast_lputfield" , "bjj" , null , BasicType.getTLong() , 0, true , _putfield ); - def(_fast_sputfield , "fast_sputfield" , "bjj" , null , BasicType.getTShort() , 0, true , _putfield ); + def(_fast_aputfield , "fast_aputfield" , "bJJ" , null , BasicType.getTObject() , 0, true , _putfield ); + def(_fast_bputfield , "fast_bputfield" , "bJJ" , null , BasicType.getTInt() , 0, true , _putfield ); + def(_fast_cputfield , "fast_cputfield" , "bJJ" , null , BasicType.getTChar() , 0, true , _putfield ); + def(_fast_dputfield , "fast_dputfield" , "bJJ" , null , BasicType.getTDouble() , 0, true , _putfield ); + def(_fast_fputfield , "fast_fputfield" , "bJJ" , null , BasicType.getTFloat() , 0, true , _putfield ); + def(_fast_iputfield , "fast_iputfield" , "bJJ" , null , BasicType.getTInt() , 0, true , _putfield ); + def(_fast_lputfield , "fast_lputfield" , "bJJ" , null , BasicType.getTLong() , 0, true , _putfield ); + def(_fast_sputfield , "fast_sputfield" , "bJJ" , null , BasicType.getTShort() , 0, true , _putfield ); def(_fast_aload_0 , "fast_aload_0" , "b" , null , BasicType.getTObject() , 1, true , _aload_0 ); - def(_fast_iaccess_0 , "fast_iaccess_0" , "b_jj" , null , BasicType.getTInt() , 1, true , _aload_0 ); - def(_fast_aaccess_0 , "fast_aaccess_0" , "b_jj" , null , BasicType.getTObject() , 1, true , _aload_0 ); - def(_fast_faccess_0 , "fast_faccess_0" , "b_jj" , null , BasicType.getTObject() , 1, true , _aload_0 ); + def(_fast_iaccess_0 , "fast_iaccess_0" , "b_JJ" , null , BasicType.getTInt() , 1, true , _aload_0 ); + def(_fast_aaccess_0 , "fast_aaccess_0" , "b_JJ" , null , BasicType.getTObject() , 1, true , _aload_0 ); + def(_fast_faccess_0 , "fast_faccess_0" , "b_JJ" , null , BasicType.getTObject() , 1, true , _aload_0 ); def(_fast_iload , "fast_iload" , "bi" , null , BasicType.getTInt() , 1, false, _iload); def(_fast_iload2 , "fast_iload2" , "bi_i" , null , BasicType.getTInt() , 2, false, _iload); def(_fast_icaload , "fast_icaload" , "bi_" , null , BasicType.getTInt() , 0, false, _iload); // Faster method invocation. - def(_fast_invokevfinal , "fast_invokevfinal" , "bjj" , null , BasicType.getTIllegal(), -1, true, _invokevirtual); + def(_fast_invokevfinal , "fast_invokevfinal" , "bJJ" , null , BasicType.getTIllegal(), -1, true, _invokevirtual); def(_fast_linearswitch , "fast_linearswitch" , "" , null , BasicType.getTVoid() , -1, false, _lookupswitch ); def(_fast_binaryswitch , "fast_binaryswitch" , "" , null , BasicType.getTVoid() , -1, false, _lookupswitch ); + + def(_return_register_finalizer, "return_register_finalizer", "b" , null , BasicType.getTVoid() , 0, true, _return ); + + def(_fast_aldc , "fast_aldc" , "bj" , null , BasicType.getTObject(), 1, true, _ldc ); + def(_fast_aldc_w , "fast_aldc_w" , "bJJ" , null , BasicType.getTObject(), 1, true, _ldc_w ); + def(_shouldnotreachhere , "_shouldnotreachhere" , "b" , null , BasicType.getTVoid() , 0, false); if (Assert.ASSERTS_ENABLED) { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Wed Jul 05 17:18:12 2017 +0200 @@ -152,7 +152,7 @@ return res; } - public int getNameAndTypeAt(int which) { + public int[] getNameAndTypeAt(int which) { if (Assert.ASSERTS_ENABLED) { Assert.that(getTagAt(which).isNameAndType(), "Corrupted constant pool"); } @@ -160,18 +160,16 @@ if (DEBUG) { System.err.println("ConstantPool.getNameAndTypeAt(" + which + "): result = " + i); } - return i; + return new int[] { extractLowShortFromInt(i), extractHighShortFromInt(i) }; } public Symbol getNameRefAt(int which) { - int refIndex = getNameAndTypeAt(getNameAndTypeRefIndexAt(which)); - int nameIndex = extractLowShortFromInt(refIndex); + int nameIndex = getNameAndTypeAt(getNameAndTypeRefIndexAt(which))[0]; return getSymbolAt(nameIndex); } public Symbol getSignatureRefAt(int which) { - int refIndex = getNameAndTypeAt(getNameAndTypeRefIndexAt(which)); - int sigIndex = extractHighShortFromInt(refIndex); + int sigIndex = getNameAndTypeAt(getNameAndTypeRefIndexAt(which))[1]; return getSymbolAt(sigIndex); } @@ -220,11 +218,11 @@ /** Lookup for entries consisting of (name_index, signature_index) */ public int getNameRefIndexAt(int index) { - int refIndex = getNameAndTypeAt(index); + int[] refIndex = getNameAndTypeAt(index); if (DEBUG) { - System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): refIndex = " + refIndex); + System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): refIndex = " + refIndex[0]+"/"+refIndex[1]); } - int i = extractLowShortFromInt(refIndex); + int i = refIndex[0]; if (DEBUG) { System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): result = " + i); } @@ -233,17 +231,53 @@ /** Lookup for entries consisting of (name_index, signature_index) */ public int getSignatureRefIndexAt(int index) { - int refIndex = getNameAndTypeAt(index); + int[] refIndex = getNameAndTypeAt(index); if (DEBUG) { - System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): refIndex = " + refIndex); + System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): refIndex = " + refIndex[0]+"/"+refIndex[1]); } - int i = extractHighShortFromInt(refIndex); + int i = refIndex[1]; if (DEBUG) { System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): result = " + i); } return i; } + /** Lookup for MethodHandle entries. */ + public int getMethodHandleIndexAt(int i) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(getTagAt(i).isMethodHandle(), "Corrupted constant pool"); + } + int res = extractHighShortFromInt(getIntAt(i)); + if (DEBUG) { + System.err.println("ConstantPool.getMethodHandleIndexAt(" + i + "): result = " + res); + } + return res; + } + + /** Lookup for MethodHandle entries. */ + public int getMethodHandleRefKindAt(int i) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(getTagAt(i).isMethodHandle(), "Corrupted constant pool"); + } + int res = extractLowShortFromInt(getIntAt(i)); + if (DEBUG) { + System.err.println("ConstantPool.getMethodHandleRefKindAt(" + i + "): result = " + res); + } + return res; + } + + /** Lookup for MethodType entries. */ + public int getMethodTypeIndexAt(int i) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(getTagAt(i).isMethodType(), "Corrupted constant pool"); + } + int res = getIntAt(i); + if (DEBUG) { + System.err.println("ConstantPool.getMethodHandleTypeAt(" + i + "): result = " + res); + } + return res; + } + final private static String[] nameForTag = new String[] { }; @@ -261,6 +295,8 @@ case JVM_CONSTANT_Methodref: return "JVM_CONSTANT_Methodref"; case JVM_CONSTANT_InterfaceMethodref: return "JVM_CONSTANT_InterfaceMethodref"; case JVM_CONSTANT_NameAndType: return "JVM_CONSTANT_NameAndType"; + case JVM_CONSTANT_MethodHandle: return "JVM_CONSTANT_MethodHandle"; + case JVM_CONSTANT_MethodType: return "JVM_CONSTANT_MethodType"; case JVM_CONSTANT_Invalid: return "JVM_CONSTANT_Invalid"; case JVM_CONSTANT_UnresolvedClass: return "JVM_CONSTANT_UnresolvedClass"; case JVM_CONSTANT_UnresolvedClassInError: return "JVM_CONSTANT_UnresolvedClassInError"; @@ -317,6 +353,8 @@ case JVM_CONSTANT_Methodref: case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_NameAndType: + case JVM_CONSTANT_MethodHandle: + case JVM_CONSTANT_MethodType: visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true); break; } @@ -467,6 +505,18 @@ + ", type = " + signatureIndex); break; } + + case JVM_CONSTANT_MethodHandle: { + dos.writeByte(cpConstType); + int value = getIntAt(ci); + short nameIndex = (short) extractLowShortFromInt(value); + short signatureIndex = (short) extractHighShortFromInt(value); + dos.writeShort(nameIndex); + dos.writeShort(signatureIndex); + if (DEBUG) debugMessage("CP[" + ci + "] = N&T name = " + nameIndex + + ", type = " + signatureIndex); + break; + } default: throw new InternalError("unknown tag: " + cpConstType); } // switch @@ -488,10 +538,12 @@ // private static int extractHighShortFromInt(int val) { + // must stay in sync with constantPoolOopDesc::name_and_type_at_put, method_at_put, etc. return (val >> 16) & 0xFFFF; } private static int extractLowShortFromInt(int val) { + // must stay in sync with constantPoolOopDesc::name_and_type_at_put, method_at_put, etc. return val & 0xFFFF; } } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java Wed Jul 05 17:18:12 2017 +0200 @@ -78,6 +78,31 @@ return new ConstantPoolCacheEntry(this, i); } + public static boolean isSecondaryIndex(int i) { return (i < 0); } + public static int decodeSecondaryIndex(int i) { return isSecondaryIndex(i) ? ~i : i; } + public static int encodeSecondaryIndex(int i) { return !isSecondaryIndex(i) ? ~i : i; } + + // secondary entries hold invokedynamic call site bindings + public ConstantPoolCacheEntry getSecondaryEntryAt(int i) { + ConstantPoolCacheEntry e = new ConstantPoolCacheEntry(this, decodeSecondaryIndex(i)); + if (Assert.ASSERTS_ENABLED) { + Assert.that(e.isSecondaryEntry(), "must be a secondary entry"); + } + return e; + } + + public ConstantPoolCacheEntry getMainEntryAt(int i) { + if (isSecondaryIndex(i)) { + // run through an extra level of indirection: + i = getSecondaryEntryAt(i).getMainEntryIndex(); + } + ConstantPoolCacheEntry e = new ConstantPoolCacheEntry(this, i); + if (Assert.ASSERTS_ENABLED) { + Assert.that(!e.isSecondaryEntry(), "must not be a secondary entry"); + } + return e; + } + public int getIntAt(int entry, int fld) { //alignObjectSize ? long offset = baseOffset + /*alignObjectSize*/entry * elementSize + fld* getHeap().getIntSize(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCacheEntry.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCacheEntry.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCacheEntry.java Wed Jul 05 17:18:12 2017 +0200 @@ -28,6 +28,7 @@ import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; public class ConstantPoolCacheEntry { private static long size; @@ -67,9 +68,23 @@ } public int getConstantPoolIndex() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(!isSecondaryEntry(), "must not be a secondary CP entry"); + } return (int) (getIndices() & 0xFFFF); } + public boolean isSecondaryEntry() { + return (getIndices() & 0xFFFF) == 0; + } + + public int getMainEntryIndex() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(isSecondaryEntry(), "must be a secondary CP entry"); + } + return (int) (getIndices() >>> 16); + } + private long getIndices() { return cp.getHandle().getCIntegerAt(indices.getOffset() + offset, indices.getSize(), indices.isUnsigned()); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java Wed Jul 05 17:18:12 2017 +0200 @@ -566,6 +566,7 @@ case Bytecodes._invokespecial: case Bytecodes._invokestatic: case Bytecodes._invokeinterface: + case Bytecodes._invokedynamic: // FIXME: print signature of referenced method (need more // accessors in ConstantPool and ConstantPoolCache) int idx = currentBC.getIndexBig(); @@ -605,6 +606,7 @@ case Bytecodes._invokespecial: case Bytecodes._invokestatic: case Bytecodes._invokeinterface: + case Bytecodes._invokedynamic: // FIXME: print signature of referenced method (need more // accessors in ConstantPool and ConstantPoolCache) int idx = currentBC.getIndexBig(); @@ -1134,6 +1136,7 @@ case Bytecodes._invokespecial: case Bytecodes._invokestatic: case Bytecodes._invokeinterface: + case Bytecodes._invokedynamic: _itr_send = itr; _report_result_for_send = true; break; @@ -1379,6 +1382,7 @@ case Bytecodes._invokevirtual: case Bytecodes._invokespecial: doMethod(false, false, itr.getIndexBig(), itr.bci()); break; case Bytecodes._invokestatic: doMethod(true, false, itr.getIndexBig(), itr.bci()); break; + case Bytecodes._invokedynamic: doMethod(false, true, itr.getIndexBig(), itr.bci()); break; case Bytecodes._invokeinterface: doMethod(false, true, itr.getIndexBig(), itr.bci()); break; case Bytecodes._newarray: case Bytecodes._anewarray: ppNewRef(vCTS, itr.bci()); break; @@ -1725,7 +1729,7 @@ void doMethod (boolean is_static, boolean is_interface, int idx, int bci) { // Dig up signature for field in constant pool ConstantPool cp = _method.getConstants(); - int nameAndTypeIdx = cp.getNameAndTypeRefIndexAt(idx); + int nameAndTypeIdx = cp.getTagAt(idx).isNameAndType() ? idx : cp.getNameAndTypeRefIndexAt(idx); int signatureIdx = cp.getSignatureRefIndexAt(nameAndTypeIdx); Symbol signature = cp.getSymbolAt(signatureIdx); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Wed Jul 05 17:18:12 2017 +0200 @@ -40,6 +40,19 @@ public static final int JVM_CONSTANT_Methodref = 10; public static final int JVM_CONSTANT_InterfaceMethodref = 11; public static final int JVM_CONSTANT_NameAndType = 12; + public static final int JVM_CONSTANT_MethodHandle = 15; + public static final int JVM_CONSTANT_MethodType = 16; + + // JVM_CONSTANT_MethodHandle subtypes + public static final int JVM_REF_getField = 1; + public static final int JVM_REF_getStatic = 2; + public static final int JVM_REF_putField = 3; + public static final int JVM_REF_putStatic = 4; + public static final int JVM_REF_invokeVirtual = 5; + public static final int JVM_REF_invokeStatic = 6; + public static final int JVM_REF_invokeSpecial = 7; + public static final int JVM_REF_newInvokeSpecial = 8; + public static final int JVM_REF_invokeInterface = 9; // HotSpot specific constant pool constant types. diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java Wed Jul 05 17:18:12 2017 +0200 @@ -54,14 +54,34 @@ } - protected short getConstantPoolIndex(int bci) { + protected short getConstantPoolIndex(int rawcode, int bci) { // get ConstantPool index from ConstantPoolCacheIndex at given bci - short cpCacheIndex = method.getBytecodeShortArg(bci); + String fmt = Bytecodes.format(rawcode); + int cpCacheIndex; + switch (fmt.length()) { + case 2: cpCacheIndex = method.getBytecodeByteArg(bci); break; + case 3: cpCacheIndex = method.getBytecodeShortArg(bci); break; + case 5: + if (fmt.indexOf("__") >= 0) + cpCacheIndex = method.getBytecodeShortArg(bci); + else + cpCacheIndex = method.getBytecodeIntArg(bci); + break; + default: throw new IllegalArgumentException(); + } if (cpCache == null) { - return cpCacheIndex; + return (short) cpCacheIndex; + } else if (fmt.indexOf("JJJJ") >= 0) { + // change byte-ordering and go via secondary cache entry + return (short) cpCache.getMainEntryAt(bytes.swapInt(cpCacheIndex)).getConstantPoolIndex(); + } else if (fmt.indexOf("JJ") >= 0) { + // change byte-ordering and go via cache + return (short) cpCache.getEntryAt((int) (0xFFFF & bytes.swapShort((short)cpCacheIndex))).getConstantPoolIndex(); + } else if (fmt.indexOf("j") >= 0) { + // go via cache + return (short) cpCache.getEntryAt((int) (0xFF & cpCacheIndex)).getConstantPoolIndex(); } else { - // change byte-ordering and go via cache - return (short) cpCache.getEntryAt((int) (0xFFFF & bytes.swapShort(cpCacheIndex))).getConstantPoolIndex(); + return (short) cpCacheIndex; } } @@ -100,10 +120,31 @@ case Bytecodes._invokespecial: case Bytecodes._invokestatic: case Bytecodes._invokeinterface: { - cpoolIndex = getConstantPoolIndex(bci + 1); + cpoolIndex = getConstantPoolIndex(hotspotcode, bci + 1); writeShort(code, bci + 1, cpoolIndex); break; } + + case Bytecodes._invokedynamic: + cpoolIndex = getConstantPoolIndex(hotspotcode, bci + 1); + writeShort(code, bci + 1, cpoolIndex); + writeShort(code, bci + 3, (short)0); // clear out trailing bytes + break; + + case Bytecodes._ldc_w: + if (hotspotcode != bytecode) { + // fast_aldc_w puts constant in CP cache + cpoolIndex = getConstantPoolIndex(hotspotcode, bci + 1); + writeShort(code, bci + 1, cpoolIndex); + } + break; + case Bytecodes._ldc: + if (hotspotcode != bytecode) { + // fast_aldc puts constant in CP cache + cpoolIndex = getConstantPoolIndex(hotspotcode, bci + 1); + code[bci + 1] = (byte)(cpoolIndex); + } + break; } len = Bytecodes.lengthFor(bytecode); diff -r c4a3e3140f7b -r 88db80c8e49c 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 Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java Wed Jul 05 17:18:12 2017 +0200 @@ -61,10 +61,12 @@ protected short _signatureIndex; protected static int extractHighShortFromInt(int val) { + // must stay in sync with constantPoolOopDesc::name_and_type_at_put, method_at_put, etc. return (val >> 16) & 0xFFFF; } protected static int extractLowShortFromInt(int val) { + // must stay in sync with constantPoolOopDesc::name_and_type_at_put, method_at_put, etc. return val & 0xFFFF; } @@ -297,6 +299,28 @@ + ", type = " + signatureIndex); break; } + + case JVM_CONSTANT_MethodHandle: { + dos.writeByte(cpConstType); + int value = cpool.getIntAt(ci); + short refIndex = (short) extractHighShortFromInt(value); + byte refKind = (byte) extractLowShortFromInt(value); + dos.writeByte(refKind); + dos.writeShort(refIndex); + if (DEBUG) debugMessage("CP[" + ci + "] = MH index = " + refIndex + + ", kind = " + refKind); + break; + } + + case JVM_CONSTANT_MethodType: { + dos.writeByte(cpConstType); + int value = cpool.getIntAt(ci); + short refIndex = (short) value; + dos.writeShort(refIndex); + if (DEBUG) debugMessage("CP[" + ci + "] = MT index = " + refIndex); + break; + } + default: throw new InternalError("Unknown tag: " + cpConstType); } // switch diff -r c4a3e3140f7b -r 88db80c8e49c 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 Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Wed Jul 05 17:18:12 2017 +0200 @@ -572,6 +572,16 @@ buf.cell(Integer.toString(cpool.getIntAt(index))); break; + case JVM_CONSTANT_MethodHandle: + buf.cell("JVM_CONSTANT_MethodHandle"); + buf.cell(genLowHighShort(cpool.getIntAt(index))); + break; + + case JVM_CONSTANT_MethodType: + buf.cell("JVM_CONSTANT_MethodType"); + buf.cell(Integer.toString(cpool.getIntAt(index))); + break; + default: throw new InternalError("unknown tag: " + ctag); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Wed Jul 05 17:18:12 2017 +0200 @@ -38,12 +38,26 @@ private static int JVM_CONSTANT_Methodref = 10; private static int JVM_CONSTANT_InterfaceMethodref = 11; 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_Invalid = 0; // For bad value initialization private static int JVM_CONSTANT_UnresolvedClass = 100; // Temporary tag until actual use private static int JVM_CONSTANT_ClassIndex = 101; // Temporary tag while constructing constant pool private static int JVM_CONSTANT_UnresolvedString = 102; // Temporary tag until actual use private static int JVM_CONSTANT_StringIndex = 103; // Temporary tag while constructing constant pool private static int JVM_CONSTANT_UnresolvedClassInError = 104; // Resolution failed + private static int JVM_CONSTANT_Object = 105; // Required for BoundMethodHandle arguments. + + // JVM_CONSTANT_MethodHandle subtypes //FIXME: connect these to data structure + private static int JVM_REF_getField = 1; + private static int JVM_REF_getStatic = 2; + private static int JVM_REF_putField = 3; + private static int JVM_REF_putStatic = 4; + private static int JVM_REF_invokeVirtual = 5; + private static int JVM_REF_invokeStatic = 6; + private static int JVM_REF_invokeSpecial = 7; + private static int JVM_REF_newInvokeSpecial = 8; + private static int JVM_REF_invokeInterface = 9; private byte tag; @@ -62,6 +76,8 @@ public boolean isDouble() { return tag == JVM_CONSTANT_Double; } public boolean isNameAndType() { return tag == JVM_CONSTANT_NameAndType; } public boolean isUtf8() { return tag == JVM_CONSTANT_Utf8; } + public boolean isMethodHandle() { return tag == JVM_CONSTANT_MethodHandle; } + public boolean isMethodType() { return tag == JVM_CONSTANT_MethodType; } public boolean isInvalid() { return tag == JVM_CONSTANT_Invalid; } @@ -73,6 +89,8 @@ public boolean isUnresolvedString() { return tag == JVM_CONSTANT_UnresolvedString; } public boolean isStringIndex() { return tag == JVM_CONSTANT_StringIndex; } + public boolean isObject() { return tag == JVM_CONSTANT_Object; } + public boolean isKlassReference() { return isKlassIndex() || isUnresolvedKlass(); } public boolean isFieldOrMethod() { return isField() || isMethod() || isInterfaceMethod(); } public boolean isSymbol() { return isUtf8(); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js Wed Jul 05 17:18:12 2017 +0200 @@ -825,6 +825,8 @@ } writeln(""); disAsm.decode(new sapkg.interpreter.BytecodeVisitor() { + prologue: function(method) { }, + epilogue: function() { }, visit: function(bytecode) { if (hasLines) { var line = method.getLineNumberFromBCI(bci); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/make/hotspot_version --- a/hotspot/make/hotspot_version Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/make/hotspot_version Wed Jul 05 17:18:12 2017 +0200 @@ -35,7 +35,7 @@ HS_MAJOR_VER=19 HS_MINOR_VER=0 -HS_BUILD_NUMBER=03 +HS_BUILD_NUMBER=04 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/make/linux/makefiles/adlc.make --- a/hotspot/make/linux/makefiles/adlc.make Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/make/linux/makefiles/adlc.make Wed Jul 05 17:18:12 2017 +0200 @@ -138,7 +138,11 @@ # Normally, debugging is done directly on the ad_*.cpp files. # But -g will put #line directives in those files pointing back to .ad. +# Some builds of gcc 3.2 have a bug that gets tickled by the extra #line directives +# so skip it for 3.2 and ealier. +ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" ADLCFLAGS += -g +endif ifdef LP64 ADLCFLAGS += -D_LP64 diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/make/linux/makefiles/sa.make --- a/hotspot/make/linux/makefiles/sa.make Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/make/linux/makefiles/sa.make Wed Jul 05 17:18:12 2017 +0200 @@ -40,6 +40,9 @@ # tools.jar is needed by the JDI - SA binding SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar +# TODO: if it's a modules image, check if SA module is installed. +MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules + # gnumake 3.78.1 does not accept the *s that # are in AGENT_FILES1 and AGENT_FILES2, so use the shell to expand them AGENT_FILES1 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES1)) @@ -65,7 +68,7 @@ echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ exit 1; \ fi - $(QUIETLY) if [ ! -f $(SA_CLASSPATH) ] ; then \ + $(QUIETLY) if [ ! -f $(SA_CLASSPATH) -a ! -d $(MODULELIB_PATH) ] ; then \ echo "Missing $(SA_CLASSPATH) file. Use 1.6.0 or later version of JDK";\ echo ""; \ exit 1; \ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/make/solaris/makefiles/sa.make --- a/hotspot/make/solaris/makefiles/sa.make Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/make/solaris/makefiles/sa.make Wed Jul 05 17:18:12 2017 +0200 @@ -36,6 +36,9 @@ # tools.jar is needed by the JDI - SA binding SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar +# TODO: if it's a modules image, check if SA module is installed. +MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules + # gnumake 3.78.1 does not accept the *s that # are in AGENT_FILES1 and AGENT_FILES2, so use the shell to expand them AGENT_FILES1 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES1)) @@ -59,7 +62,7 @@ echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ exit 1; \ fi - $(QUIETLY) if [ ! -f $(SA_CLASSPATH) ] ; then \ + $(QUIETLY) if [ ! -f $(SA_CLASSPATH) -a ! -d $(MODULELIB_PATH) ] ; then \ echo "Missing $(SA_CLASSPATH) file. Use 1.6.0 or later version of JDK";\ echo ""; \ exit 1; \ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -318,6 +318,31 @@ __ bind(exit); } +// Fast path for caching oop constants. +// %%% We should use this to handle Class and String constants also. +// %%% It will simplify the ldc/primitive path considerably. +void TemplateTable::fast_aldc(bool wide) { + transition(vtos, atos); + + if (!EnableMethodHandles) { + // We should not encounter this bytecode if !EnableMethodHandles. + // The verifier will stop it. However, if we get past the verifier, + // this will stop the thread in a reasonable way, without crashing the JVM. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_IncompatibleClassChangeError)); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + return; + } + + Register Rcache = G3_scratch; + Register Rscratch = G4_scratch; + + resolve_cache_and_index(f1_oop, Otos_i, Rcache, Rscratch, wide ? sizeof(u2) : sizeof(u1)); + + __ verify_oop(Otos_i); +} + void TemplateTable::ldc2_w() { transition(vtos, vtos); Label retry, resolved, Long, exit; @@ -1994,6 +2019,8 @@ case Bytecodes::_invokestatic : // fall through case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; + case Bytecodes::_fast_aldc : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; + case Bytecodes::_fast_aldc_w : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; default : ShouldNotReachHere(); break; } // first time invocation - must resolve first diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -375,6 +375,32 @@ __ bind(Done); } +// Fast path for caching oop constants. +// %%% We should use this to handle Class and String constants also. +// %%% It will simplify the ldc/primitive path considerably. +void TemplateTable::fast_aldc(bool wide) { + transition(vtos, atos); + + if (!EnableMethodHandles) { + // We should not encounter this bytecode if !EnableMethodHandles. + // The verifier will stop it. However, if we get past the verifier, + // this will stop the thread in a reasonable way, without crashing the JVM. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_IncompatibleClassChangeError)); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + return; + } + + const Register cache = rcx; + const Register index = rdx; + + resolve_cache_and_index(f1_oop, rax, cache, index, wide ? sizeof(u2) : sizeof(u1)); + if (VerifyOops) { + __ verify_oop(rax); + } +} + void TemplateTable::ldc2_w() { transition(vtos, vtos); Label Long, Done; @@ -2055,6 +2081,8 @@ case Bytecodes::_invokestatic : // fall through case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; + case Bytecodes::_fast_aldc : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; + case Bytecodes::_fast_aldc_w : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; default : ShouldNotReachHere(); break; } __ movl(temp, (int)bytecode()); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -389,6 +389,32 @@ __ bind(Done); } +// Fast path for caching oop constants. +// %%% We should use this to handle Class and String constants also. +// %%% It will simplify the ldc/primitive path considerably. +void TemplateTable::fast_aldc(bool wide) { + transition(vtos, atos); + + if (!EnableMethodHandles) { + // We should not encounter this bytecode if !EnableMethodHandles. + // The verifier will stop it. However, if we get past the verifier, + // this will stop the thread in a reasonable way, without crashing the JVM. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_IncompatibleClassChangeError)); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + return; + } + + const Register cache = rcx; + const Register index = rdx; + + resolve_cache_and_index(f1_oop, rax, cache, index, wide ? sizeof(u2) : sizeof(u1)); + if (VerifyOops) { + __ verify_oop(rax); + } +} + void TemplateTable::ldc2_w() { transition(vtos, vtos); Label Long, Done; @@ -2063,6 +2089,12 @@ case Bytecodes::_invokedynamic: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; + case Bytecodes::_fast_aldc: + entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); + break; + case Bytecodes::_fast_aldc_w: + entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); + break; default: ShouldNotReachHere(); break; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/cpu/x86/vm/vm_version_x86.cpp --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, }; static BufferBlob* stub_blob; -static const int stub_size = 300; +static const int stub_size = 400; extern "C" { typedef void (*getPsrInfo_stub_t)(void*); @@ -56,7 +56,7 @@ const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT); const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT); - Label detect_486, cpu486, detect_586, std_cpuid1; + Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4; Label ext_cpuid1, ext_cpuid5, done; StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub"); @@ -131,13 +131,62 @@ __ movl(Address(rsi, 8), rcx); __ movl(Address(rsi,12), rdx); - __ cmpl(rax, 3); // Is cpuid(0x4) supported? - __ jccb(Assembler::belowEqual, std_cpuid1); + __ cmpl(rax, 0xa); // Is cpuid(0xB) supported? + __ jccb(Assembler::belowEqual, std_cpuid4); + + // + // cpuid(0xB) Processor Topology + // + __ movl(rax, 0xb); + __ xorl(rcx, rcx); // Threads level + __ cpuid(); + + __ lea(rsi, Address(rbp, in_bytes(VM_Version::tpl_cpuidB0_offset()))); + __ movl(Address(rsi, 0), rax); + __ movl(Address(rsi, 4), rbx); + __ movl(Address(rsi, 8), rcx); + __ movl(Address(rsi,12), rdx); + + __ movl(rax, 0xb); + __ movl(rcx, 1); // Cores level + __ cpuid(); + __ push(rax); + __ andl(rax, 0x1f); // Determine if valid topology level + __ orl(rax, rbx); // eax[4:0] | ebx[0:15] == 0 indicates invalid level + __ andl(rax, 0xffff); + __ pop(rax); + __ jccb(Assembler::equal, std_cpuid4); + + __ lea(rsi, Address(rbp, in_bytes(VM_Version::tpl_cpuidB1_offset()))); + __ movl(Address(rsi, 0), rax); + __ movl(Address(rsi, 4), rbx); + __ movl(Address(rsi, 8), rcx); + __ movl(Address(rsi,12), rdx); + + __ movl(rax, 0xb); + __ movl(rcx, 2); // Packages level + __ cpuid(); + __ push(rax); + __ andl(rax, 0x1f); // Determine if valid topology level + __ orl(rax, rbx); // eax[4:0] | ebx[0:15] == 0 indicates invalid level + __ andl(rax, 0xffff); + __ pop(rax); + __ jccb(Assembler::equal, std_cpuid4); + + __ lea(rsi, Address(rbp, in_bytes(VM_Version::tpl_cpuidB2_offset()))); + __ movl(Address(rsi, 0), rax); + __ movl(Address(rsi, 4), rbx); + __ movl(Address(rsi, 8), rcx); + __ movl(Address(rsi,12), rdx); // // cpuid(0x4) Deterministic cache params // + __ bind(std_cpuid4); __ movl(rax, 4); + __ cmpl(rax, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); // Is cpuid(0x4) supported? + __ jccb(Assembler::greater, std_cpuid1); + __ xorl(rcx, rcx); // L1 cache __ cpuid(); __ push(rax); @@ -460,13 +509,18 @@ AllocatePrefetchDistance = allocate_prefetch_distance(); AllocatePrefetchStyle = allocate_prefetch_style(); - if( AllocatePrefetchStyle == 2 && is_intel() && - cpu_family() == 6 && supports_sse3() ) { // watermark prefetching on Core + if( is_intel() && cpu_family() == 6 && supports_sse3() ) { + if( AllocatePrefetchStyle == 2 ) { // watermark prefetching on Core #ifdef _LP64 - AllocatePrefetchDistance = 384; + AllocatePrefetchDistance = 384; #else - AllocatePrefetchDistance = 320; + AllocatePrefetchDistance = 320; #endif + } + if( supports_sse4_2() && supports_ht() ) { // Nehalem based cpus + AllocatePrefetchDistance = 192; + AllocatePrefetchLines = 4; + } } assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value"); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/cpu/x86/vm/vm_version_x86.hpp --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,6 +114,14 @@ } bits; }; + union TplCpuidBEbx { + uint32_t value; + struct { + uint32_t logical_cpus : 16, + : 16; + } bits; + }; + union ExtCpuid1Ecx { uint32_t value; struct { @@ -211,6 +219,25 @@ uint32_t dcp_cpuid4_ecx; // unused currently uint32_t dcp_cpuid4_edx; // unused currently + // cpuid function 0xB (processor topology) + // ecx = 0 + uint32_t tpl_cpuidB0_eax; + TplCpuidBEbx tpl_cpuidB0_ebx; + uint32_t tpl_cpuidB0_ecx; // unused currently + uint32_t tpl_cpuidB0_edx; // unused currently + + // ecx = 1 + uint32_t tpl_cpuidB1_eax; + TplCpuidBEbx tpl_cpuidB1_ebx; + uint32_t tpl_cpuidB1_ecx; // unused currently + uint32_t tpl_cpuidB1_edx; // unused currently + + // ecx = 2 + uint32_t tpl_cpuidB2_eax; + TplCpuidBEbx tpl_cpuidB2_ebx; + uint32_t tpl_cpuidB2_ecx; // unused currently + uint32_t tpl_cpuidB2_edx; // unused currently + // cpuid function 0x80000000 // example, unused uint32_t ext_max_function; uint32_t ext_vendor_name_0; @@ -316,6 +343,9 @@ static ByteSize ext_cpuid1_offset() { return byte_offset_of(CpuidInfo, ext_cpuid1_eax); } static ByteSize ext_cpuid5_offset() { return byte_offset_of(CpuidInfo, ext_cpuid5_eax); } static ByteSize ext_cpuid8_offset() { return byte_offset_of(CpuidInfo, ext_cpuid8_eax); } + static ByteSize tpl_cpuidB0_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB0_eax); } + static ByteSize tpl_cpuidB1_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB1_eax); } + static ByteSize tpl_cpuidB2_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB2_eax); } // Initialization static void initialize(); @@ -346,10 +376,22 @@ static bool is_amd() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x68747541; } // 'htuA' static bool is_intel() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x756e6547; } // 'uneG' + static bool supports_processor_topology() { + return (_cpuid_info.std_max_function >= 0xB) && + // eax[4:0] | ebx[0:15] == 0 indicates invalid topology level. + // Some cpus have max cpuid >= 0xB but do not support processor topology. + ((_cpuid_info.tpl_cpuidB0_eax & 0x1f | _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus) != 0); + } + static uint cores_per_cpu() { uint result = 1; if (is_intel()) { - result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1); + if (supports_processor_topology()) { + result = _cpuid_info.tpl_cpuidB1_ebx.bits.logical_cpus / + _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus; + } else { + result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1); + } } else if (is_amd()) { result = (_cpuid_info.ext_cpuid8_ecx.bits.cores_per_cpu + 1); } @@ -358,7 +400,9 @@ static uint threads_per_core() { uint result = 1; - if (_cpuid_info.std_cpuid1_edx.bits.ht != 0) { + if (is_intel() && supports_processor_topology()) { + result = _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus; + } else if (_cpuid_info.std_cpuid1_edx.bits.ht != 0) { result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu / cores_per_cpu(); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -820,7 +820,7 @@ bool is_top_frame) { assert(popframe_extra_args == 0, "what to do?"); assert(!is_top_frame || (!callee_locals && !callee_param_count), - "top frame should have no caller") + "top frame should have no caller"); // This code must exactly match what InterpreterFrame::build // does (the full InterpreterFrame::build, that is, not the diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -2079,9 +2079,9 @@ static char saved_jvm_path[MAXPATHLEN] = {0}; // Find the full path to the current module, libjvm.so or libjvm_g.so -void os::jvm_path(char *buf, jint len) { +void os::jvm_path(char *buf, jint buflen) { // Error checking. - if (len < MAXPATHLEN) { + if (buflen < MAXPATHLEN) { assert(false, "must use a large-enough buffer"); buf[0] = '\0'; return; @@ -2117,6 +2117,9 @@ // Look for JAVA_HOME in the environment. char* java_home_var = ::getenv("JAVA_HOME"); if (java_home_var != NULL && java_home_var[0] != 0) { + char* jrelib_p; + int len; + // Check the current module name "libjvm.so" or "libjvm_g.so". p = strrchr(buf, '/'); assert(strstr(p, "/libjvm") == p, "invalid library name"); @@ -2124,14 +2127,24 @@ if (realpath(java_home_var, buf) == NULL) return; - sprintf(buf + strlen(buf), "/jre/lib/%s", cpu_arch); + + // determine if this is a legacy image or modules image + // modules image doesn't have "jre" subdirectory + len = strlen(buf); + jrelib_p = buf + len; + snprintf(jrelib_p, buflen-len, "/jre/lib/%s", cpu_arch); + if (0 != access(buf, F_OK)) { + snprintf(jrelib_p, buflen-len, "/lib/%s", cpu_arch); + } + if (0 == access(buf, F_OK)) { // Use current module name "libjvm[_g].so" instead of // "libjvm"debug_only("_g")".so" since for fastdebug version // we should have "libjvm.so" but debug_only("_g") adds "_g"! // It is used when we are choosing the HPI library's name // "libhpi[_g].so" in hpi::initialize_get_interface(). - sprintf(buf + strlen(buf), "/hotspot/libjvm%s.so", p); + len = strlen(buf); + snprintf(buf + len, buflen-len, "/hotspot/libjvm%s.so", p); } else { // Go back to path of .so if (realpath(dli_fname, buf) == NULL) diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os/linux/vm/vtune_linux.cpp --- a/hotspot/src/os/linux/vm/vtune_linux.cpp Wed Jul 05 17:17:22 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. - * 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 "incls/_precompiled.incl" -#include "incls/_vtune_linux.cpp.incl" - -// empty implementation - -void VTune::start_GC() {} -void VTune::end_GC() {} -void VTune::start_class_load() {} -void VTune::end_class_load() {} -void VTune::exit() {} -void VTune::register_stub(const char* name, address start, address end) {} - -void VTune::create_nmethod(nmethod* nm) {} -void VTune::delete_nmethod(nmethod* nm) {} - -void vtune_init() {} - - -// Reconciliation History -// vtune_solaris.cpp 1.8 99/07/12 23:54:21 -// End diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os/solaris/vm/osThread_solaris.hpp --- a/hotspot/src/os/solaris/vm/osThread_solaris.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/os/solaris/vm/osThread_solaris.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -123,7 +123,7 @@ int set_interrupt_callback (Sync_Interrupt_Callback * cb); void remove_interrupt_callback(Sync_Interrupt_Callback * cb); - void OSThread::do_interrupt_callbacks_at_interrupt(InterruptArguments *args); + void do_interrupt_callbacks_at_interrupt(InterruptArguments *args); // *************************************************************** // java.lang.Thread.interrupt state. diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -2435,6 +2435,8 @@ char* java_home_var = ::getenv("JAVA_HOME"); if (java_home_var != NULL && java_home_var[0] != 0) { char cpu_arch[12]; + char* jrelib_p; + int len; sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch)); #ifdef _LP64 // If we are on sparc running a 64-bit vm, look in jre/lib/sparcv9. @@ -2450,14 +2452,23 @@ p = strstr(p, "_g") ? "_g" : ""; realpath(java_home_var, buf); - sprintf(buf + strlen(buf), "/jre/lib/%s", cpu_arch); + // determine if this is a legacy image or modules image + // modules image doesn't have "jre" subdirectory + len = strlen(buf); + jrelib_p = buf + len; + snprintf(jrelib_p, buflen-len, "/jre/lib/%s", cpu_arch); + if (0 != access(buf, F_OK)) { + snprintf(jrelib_p, buflen-len, "/lib/%s", cpu_arch); + } + if (0 == access(buf, F_OK)) { // Use current module name "libjvm[_g].so" instead of // "libjvm"debug_only("_g")".so" since for fastdebug version // we should have "libjvm.so" but debug_only("_g") adds "_g"! // It is used when we are choosing the HPI library's name // "libhpi[_g].so" in hpi::initialize_get_interface(). - sprintf(buf + strlen(buf), "/hotspot/libjvm%s.so", p); + len = strlen(buf); + snprintf(buf + len, buflen-len, "/hotspot/libjvm%s.so", p); } else { // Go back to path of .so realpath((char *)dlinfo.dli_fname, buf); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os/solaris/vm/vtune_solaris.cpp --- a/hotspot/src/os/solaris/vm/vtune_solaris.cpp Wed Jul 05 17:17:22 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. - * 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 "incls/_precompiled.incl" -#include "incls/_vtune_solaris.cpp.incl" - -// empty implementation - -void VTune::start_GC() {} -void VTune::end_GC() {} -void VTune::start_class_load() {} -void VTune::end_class_load() {} -void VTune::exit() {} -void VTune::register_stub(const char* name, address start, address end) {} - -void VTune::create_nmethod(nmethod* nm) {} -void VTune::delete_nmethod(nmethod* nm) {} - -void vtune_init() {} diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os/windows/vm/vtune_windows.cpp --- a/hotspot/src/os/windows/vm/vtune_windows.cpp Wed Jul 05 17:17:22 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,290 +0,0 @@ -/* - * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. - * 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 "incls/_precompiled.incl" -#include "incls/_vtune_windows.cpp.incl" - -static int current_method_ID = 0; - -// ------------- iJITProf.h ------------------- -// defined by Intel -- do not change - -#include "windows.h" - -extern "C" { - enum iJITP_Event { - ExceptionOccurred_S, // Java exception - ExceptionOccurred_IDS, - - Shutdown, // VM exit - - ThreadCreate, // threads - ThreadDestroy, - ThreadSwitch, - - ClassLoadStart, // class loading - ClassLoadEnd, - - GCStart, // GC - GCEnd, - - NMethodCreate = 13, // nmethod creation - NMethodDelete - - // rest of event types omitted (call profiling not supported yet) - }; - - // version number -- 0 if VTune not installed - int WINAPI iJitP_VersionNumber(); - - enum iJITP_ModeFlags { - NoNotification = 0x0, // don't call vtune - NotifyNMethodCreate = 0x1, // notify NMethod_Create - NotifyNMethodDelete = 0x2, // notify NMethod_Create - NotifyMethodEnter = 0x4, // method entry - NotifyMethodExit = 0x8, // method exit - NotifyShutdown = 0x10, // VM exit - NotifyGC = 0x20, // GC - }; - - // call back function type - typedef void (WINAPI *ModeChangedFn)(iJITP_ModeFlags flags); - - // ------------- VTune method interfaces ---------------------- - typedef void (WINAPI *RegisterCallbackFn)(ModeChangedFn fn); // register callback - typedef int (WINAPI *NotifyEventFn)(iJITP_Event, void* event_data); - - // specific event data structures - - // data for NMethodCreate - - struct VTuneObj { // base class for allocation - // (can't use CHeapObj -- has vtable ptr) - void* operator new(size_t size) { return os::malloc(size); } - void operator delete(void* p) { fatal("never delete VTune data"); } - }; - - struct LineNumberInfo : VTuneObj { // PC-to-line number mapping - unsigned long offset; // byte offset from start of method - unsigned long line_num; // corresponding line number - }; - - struct MethodLoadInfo : VTuneObj { - unsigned long methodID; // unique method ID - const char* name; // method name - unsigned long instr_start; // start address - unsigned long instr_size; // length in bytes - unsigned long line_number_size; // size of line number table - LineNumberInfo* line_number_table; // line number mapping - unsigned long classID; // unique class ID - char* class_file_name; // fully qualified class file name - char* source_file_name; // fully qualified source file name - - MethodLoadInfo(nmethod* nm); // for real nmethods - MethodLoadInfo(const char* vm_name, address start, address end); - // for "nmethods" like stubs, interpreter, etc - - }; - - // data for NMethodDelete - struct MethodInfo : VTuneObj { - unsigned long methodID; // unique method ID - unsigned long classID; // (added for convenience -- not part of Intel interface) - - MethodInfo(methodOop m); - }; -}; - -MethodInfo::MethodInfo(methodOop m) { - // just give it a new ID -- we're not compiling methods twice (usually) - // (and even if we did, one might want to see the two versions separately) - methodID = ++current_method_ID; -} - -MethodLoadInfo::MethodLoadInfo(const char* vm_name, address start, address end) { - classID = 0; - methodID = ++current_method_ID; - name = vm_name; - instr_start = (unsigned long)start; - instr_size = end - start; - line_number_size = 0; - line_number_table = NULL; - class_file_name = source_file_name = "HotSpot JVM"; -} - -MethodLoadInfo::MethodLoadInfo(nmethod* nm) { - methodOop m = nm->method(); - MethodInfo info(m); - classID = info.classID; - methodID = info.methodID; - name = strdup(m->name()->as_C_string()); - instr_start = (unsigned long)nm->instructions_begin(); - instr_size = nm->code_size(); - line_number_size = 0; - line_number_table = NULL; - klassOop kl = m->method_holder(); - char* class_name = Klass::cast(kl)->name()->as_C_string(); - char* file_name = NEW_C_HEAP_ARRAY(char, strlen(class_name) + 1); - strcpy(file_name, class_name); - class_file_name = file_name; - char* src_name = NEW_C_HEAP_ARRAY(char, strlen(class_name) + strlen(".java") + 1); - strcpy(src_name, class_name); - strcat(src_name, ".java"); - source_file_name = src_name; -} - -// --------------------- DLL loading functions ------------------------ - -#define DLLNAME "iJitProf.dll" - -static HINSTANCE load_lib(char* name) { - HINSTANCE lib = NULL; - HKEY hk; - - // try to get VTune directory from the registry - if (RegOpenKey(HKEY_CURRENT_USER, "Software\\VB and VBA Program Settings\\VTune\\StartUp", &hk) == ERROR_SUCCESS) { - for (int i = 0; true; i++) { - char szName[MAX_PATH + 1]; - char szVal [MAX_PATH + 1]; - DWORD cbName, cbVal; - - cbName = cbVal = MAX_PATH + 1; - if (RegEnumValue(hk, i, szName, &cbName, NULL, NULL, (LPBYTE)szVal, &cbVal) == ERROR_SUCCESS) { - // get VTune directory - if (!strcmp(szName, name)) { - char*p = szVal; - while (*p == ' ') p++; // trim - char* q = p + strlen(p) - 1; - while (*q == ' ') *(q--) = '\0'; - - // chdir to the VTune dir - GetCurrentDirectory(MAX_PATH + 1, szName); - SetCurrentDirectory(p); - // load lib - lib = LoadLibrary(strcat(strcat(p, "\\"), DLLNAME)); - if (lib != NULL && WizardMode) tty->print_cr("*loaded VTune DLL %s", p); - // restore current dir - SetCurrentDirectory(szName); - break; - } - } else { - break; - } - } - } - return lib; -} - -static RegisterCallbackFn iJIT_RegisterCallback = NULL; -static NotifyEventFn iJIT_NotifyEvent = NULL; - -static bool load_iJIT_funcs() { - // first try to load from PATH - HINSTANCE lib = LoadLibrary(DLLNAME); - if (lib != NULL && WizardMode) tty->print_cr("*loaded VTune DLL %s via PATH", DLLNAME); - - // if not successful, try to look in the VTUNE directory - if (lib == NULL) lib = load_lib("VTUNEDIR30"); - if (lib == NULL) lib = load_lib("VTUNEDIR25"); - if (lib == NULL) lib = load_lib("VTUNEDIR"); - - if (lib == NULL) return false; // unsuccessful - - // try to load the functions - iJIT_RegisterCallback = (RegisterCallbackFn)GetProcAddress(lib, "iJIT_RegisterCallback"); - iJIT_NotifyEvent = (NotifyEventFn) GetProcAddress(lib, "iJIT_NotifyEvent"); - - if (!iJIT_RegisterCallback) tty->print_cr("*couldn't find VTune entry point iJIT_RegisterCallback"); - if (!iJIT_NotifyEvent) tty->print_cr("*couldn't find VTune entry point iJIT_NotifyEvent"); - return iJIT_RegisterCallback != NULL && iJIT_NotifyEvent != NULL; -} - -// --------------------- VTune class ------------------------ - -static bool active = false; -static int flags = 0; - -void VTune::start_GC() { - if (active && (flags & NotifyGC)) iJIT_NotifyEvent(GCStart, NULL); -} - -void VTune::end_GC() { - if (active && (flags & NotifyGC)) iJIT_NotifyEvent(GCEnd, NULL); -} - -void VTune::start_class_load() { - // not yet implemented in VTune -} - -void VTune::end_class_load() { - // not yet implemented in VTune -} - -void VTune::exit() { - if (active && (flags & NotifyShutdown)) iJIT_NotifyEvent(Shutdown, NULL); -} - -void VTune::register_stub(const char* name, address start, address end) { - if (flags & NotifyNMethodCreate) { - MethodLoadInfo* info = new MethodLoadInfo(name, start, end); - if (PrintMiscellaneous && WizardMode && Verbose) { - tty->print_cr("NMethodCreate %s (%d): %#x..%#x", info->name, info->methodID, - info->instr_start, info->instr_start + info->instr_size); - } - iJIT_NotifyEvent(NMethodCreate, info); - } -} - -void VTune::create_nmethod(nmethod* nm) { - if (flags & NotifyNMethodCreate) { - MethodLoadInfo* info = new MethodLoadInfo(nm); - if (PrintMiscellaneous && WizardMode && Verbose) { - tty->print_cr("NMethodCreate %s (%d): %#x..%#x", info->name, info->methodID, - info->instr_start, info->instr_start + info->instr_size); - } - iJIT_NotifyEvent(NMethodCreate, info); - } -} - -void VTune::delete_nmethod(nmethod* nm) { - if (flags & NotifyNMethodDelete) { - MethodInfo* info = new MethodInfo(nm->method()); - iJIT_NotifyEvent(NMethodDelete, info); - } -} - -static void set_flags(int new_flags) { - flags = new_flags; - // if (WizardMode) tty->print_cr("*new VTune flags: %#x", flags); -} - -void vtune_init() { - if (!UseVTune) return; - active = load_iJIT_funcs(); - if (active) { - iJIT_RegisterCallback((ModeChangedFn)set_flags); - } else { - assert(flags == 0, "flags shouldn't be set"); - } -} diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os_cpu/linux_x86/vm/copy_linux_x86.inline.hpp --- a/hotspot/src/os_cpu/linux_x86/vm/copy_linux_x86.inline.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/os_cpu/linux_x86/vm/copy_linux_x86.inline.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -26,7 +26,7 @@ #ifdef AMD64 (void)memmove(to, from, count * HeapWordSize); #else - // Same as pd_aligned_conjoint_words, except includes a zero-count check. + // Includes a zero-count check. intx temp; __asm__ volatile(" testl %6,%6 ;" " jz 7f ;" @@ -84,7 +84,7 @@ break; } #else - // Same as pd_aligned_disjoint_words, except includes a zero-count check. + // Includes a zero-count check. intx temp; __asm__ volatile(" testl %6,%6 ;" " jz 3f ;" @@ -130,75 +130,18 @@ } static void pd_aligned_conjoint_words(HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - (void)memmove(to, from, count * HeapWordSize); -#else - // Same as pd_conjoint_words, except no zero-count check. - intx temp; - __asm__ volatile(" cmpl %4,%5 ;" - " leal -4(%4,%6,4),%3;" - " jbe 1f ;" - " cmpl %7,%5 ;" - " jbe 4f ;" - "1: cmpl $32,%6 ;" - " ja 3f ;" - " subl %4,%1 ;" - "2: movl (%4),%3 ;" - " movl %7,(%5,%4,1) ;" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 2b ;" - " jmp 7f ;" - "3: rep; smovl ;" - " jmp 7f ;" - "4: cmpl $32,%2 ;" - " movl %7,%0 ;" - " leal -4(%5,%6,4),%1;" - " ja 6f ;" - " subl %4,%1 ;" - "5: movl (%4),%3 ;" - " movl %7,(%5,%4,1) ;" - " subl $4,%0 ;" - " subl $1,%2 ;" - " jnz 5b ;" - " jmp 7f ;" - "6: std ;" - " rep; smovl ;" - " cld ;" - "7: nop " - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "flags"); -#endif // AMD64 + pd_conjoint_words(from, to, count); } static void pd_aligned_disjoint_words(HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 pd_disjoint_words(from, to, count); -#else - // Same as pd_disjoint_words, except no zero-count check. - intx temp; - __asm__ volatile(" cmpl $32,%6 ;" - " ja 2f ;" - " subl %4,%1 ;" - "1: movl (%4),%3 ;" - " movl %7,(%5,%4,1);" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 1b ;" - " jmp 3f ;" - "2: rep; smovl ;" - "3: nop " - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "cc"); -#endif // AMD64 } static void pd_conjoint_bytes(void* from, void* to, size_t count) { #ifdef AMD64 (void)memmove(to, from, count); #else + // Includes a zero-count check. intx temp; __asm__ volatile(" testl %6,%6 ;" " jz 13f ;" diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os_cpu/linux_x86/vm/linux_x86_32.s --- a/hotspot/src/os_cpu/linux_x86/vm/linux_x86_32.s Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/os_cpu/linux_x86/vm/linux_x86_32.s Wed Jul 05 17:18:12 2017 +0200 @@ -121,10 +121,10 @@ jnz 3b addl %esi,%edi 4: movl %eax,%ecx # byte count less prefix - andl $3,%ecx # suffix byte count +5: andl $3,%ecx # suffix byte count jz 7f # no suffix # copy suffix -5: xorl %eax,%eax + xorl %eax,%eax 6: movb (%esi,%eax,1),%dl movb %dl,(%edi,%eax,1) addl $1,%eax @@ -159,10 +159,10 @@ # copy dwords, aligned or not 3: rep; smovl 4: movl %eax,%ecx # byte count - andl $3,%ecx # suffix byte count +5: andl $3,%ecx # suffix byte count jz 7f # no suffix # copy suffix -5: subl %esi,%edi + subl %esi,%edi addl $3,%esi 6: movb (%esi),%dl movb %dl,(%edi,%esi,1) @@ -214,10 +214,10 @@ # copy aligned dwords 3: rep; smovl 4: movl %eax,%ecx - andl $3,%ecx +5: andl $3,%ecx jz 7f # copy suffix -5: xorl %eax,%eax + xorl %eax,%eax 6: movb (%esi,%eax,1),%dl movb %dl,(%edi,%eax,1) addl $1,%eax @@ -250,9 +250,9 @@ jnz 3b addl %esi,%edi 4: movl %eax,%ecx - andl $3,%ecx +5: andl $3,%ecx jz 7f -5: subl %esi,%edi + subl %esi,%edi addl $3,%esi 6: movb (%esi),%dl movb %dl,(%edi,%esi,1) @@ -287,11 +287,12 @@ andl $3,%eax # either 0 or 2 jz 1f # no prefix # copy prefix + subl $1,%ecx + jl 5f # zero count movw (%esi),%dx movw %dx,(%edi) addl %eax,%esi # %eax == 2 addl %eax,%edi - subl $1,%ecx 1: movl %ecx,%eax # word count less prefix sarl %ecx # dword count jz 4f # no dwords to move @@ -454,12 +455,13 @@ ret .=.+10 2: subl %esi,%edi + jmp 4f .p2align 4,,15 3: movl (%esi),%edx movl %edx,(%edi,%esi,1) addl $4,%esi - subl $1,%ecx - jnz 3b +4: subl $1,%ecx + jge 3b popl %edi popl %esi ret @@ -467,19 +469,20 @@ std leal -4(%edi,%ecx,4),%edi # to + count*4 - 4 cmpl $32,%ecx - ja 3f # > 32 dwords + ja 4f # > 32 dwords subl %eax,%edi # eax == from + count*4 - 4 + jmp 3f .p2align 4,,15 2: movl (%eax),%edx movl %edx,(%edi,%eax,1) subl $4,%eax - subl $1,%ecx - jnz 2b +3: subl $1,%ecx + jge 2b cld popl %edi popl %esi ret -3: movl %eax,%esi # from + count*4 - 4 +4: movl %eax,%esi # from + count*4 - 4 rep; smovl cld popl %edi diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -861,7 +861,7 @@ cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_bootstrap; add_func_t* os::atomic_add_func = os::atomic_add_bootstrap; -extern "C" _solaris_raw_setup_fpu(address ptr); +extern "C" void _solaris_raw_setup_fpu(address ptr); void os::setup_fpu() { address fpu_cntrl = StubRoutines::addr_fpu_cntrl_wrd_std(); _solaris_raw_setup_fpu(fpu_cntrl); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.s --- a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.s Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.s Wed Jul 05 17:18:12 2017 +0200 @@ -154,10 +154,10 @@ jnz 3b addl %esi,%edi 4: movl %eax,%ecx / byte count less prefix - andl $3,%ecx / suffix byte count +5: andl $3,%ecx / suffix byte count jz 7f / no suffix / copy suffix -5: xorl %eax,%eax + xorl %eax,%eax 6: movb (%esi,%eax,1),%dl movb %dl,(%edi,%eax,1) addl $1,%eax @@ -192,10 +192,10 @@ / copy dwords, aligned or not 3: rep; smovl 4: movl %eax,%ecx / byte count - andl $3,%ecx / suffix byte count +5: andl $3,%ecx / suffix byte count jz 7f / no suffix / copy suffix -5: subl %esi,%edi + subl %esi,%edi addl $3,%esi 6: movb (%esi),%dl movb %dl,(%edi,%esi,1) @@ -246,10 +246,10 @@ / copy aligned dwords 3: rep; smovl 4: movl %eax,%ecx - andl $3,%ecx +5: andl $3,%ecx jz 7f / copy suffix -5: xorl %eax,%eax + xorl %eax,%eax 6: movb (%esi,%eax,1),%dl movb %dl,(%edi,%eax,1) addl $1,%eax @@ -282,9 +282,9 @@ jnz 3b addl %esi,%edi 4: movl %eax,%ecx - andl $3,%ecx +5: andl $3,%ecx jz 7f -5: subl %esi,%edi + subl %esi,%edi addl $3,%esi 6: movb (%esi),%dl movb %dl,(%edi,%esi,1) @@ -318,11 +318,12 @@ andl $3,%eax / either 0 or 2 jz 1f / no prefix / copy prefix + subl $1,%ecx + jl 5f / zero count movw (%esi),%dx movw %dx,(%edi) addl %eax,%esi / %eax == 2 addl %eax,%edi - subl $1,%ecx 1: movl %ecx,%eax / word count less prefix sarl %ecx / dword count jz 4f / no dwords to move @@ -482,12 +483,13 @@ ret .=.+10 2: subl %esi,%edi + jmp 4f .align 16 3: movl (%esi),%edx movl %edx,(%edi,%esi,1) addl $4,%esi - subl $1,%ecx - jnz 3b +4: subl $1,%ecx + jge 3b popl %edi popl %esi ret @@ -495,19 +497,20 @@ std leal -4(%edi,%ecx,4),%edi / to + count*4 - 4 cmpl $32,%ecx - ja 3f / > 32 dwords + ja 4f / > 32 dwords subl %eax,%edi / eax == from + count*4 - 4 + jmp 3f .align 16 2: movl (%eax),%edx movl %edx,(%edi,%eax,1) subl $4,%eax - subl $1,%ecx - jnz 2b +3: subl $1,%ecx + jge 2b cld popl %edi popl %esi ret -3: movl %eax,%esi / from + count*4 - 4 +4: movl %eax,%esi / from + count*4 - 4 rep; smovl cld popl %edi diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/asm/codeBuffer.cpp --- a/hotspot/src/share/vm/asm/codeBuffer.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -404,7 +404,7 @@ locs_start = REALLOC_RESOURCE_ARRAY(relocInfo, _locs_start, old_capacity, new_capacity); } else { locs_start = NEW_RESOURCE_ARRAY(relocInfo, new_capacity); - Copy::conjoint_bytes(_locs_start, locs_start, old_capacity * sizeof(relocInfo)); + Copy::conjoint_jbytes(_locs_start, locs_start, old_capacity * sizeof(relocInfo)); _locs_own = true; } _locs_start = locs_start; @@ -581,7 +581,7 @@ (HeapWord*)(buf+buf_offset), (lsize + HeapWordSize-1) / HeapWordSize); } else { - Copy::conjoint_bytes(lstart, buf+buf_offset, lsize); + Copy::conjoint_jbytes(lstart, buf+buf_offset, lsize); } } buf_offset += lsize; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/c1/c1_Compilation.cpp --- a/hotspot/src/share/vm/c1/c1_Compilation.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -242,10 +242,10 @@ code->insts()->initialize_shared_locs((relocInfo*)locs_buffer, locs_buffer_size / sizeof(relocInfo)); code->initialize_consts_size(Compilation::desired_max_constant_size()); - // Call stubs + deopt/exception handler + // Call stubs + two deopt handlers (regular and MH) + exception handler code->initialize_stubs_size((call_stub_estimate * LIR_Assembler::call_stub_size) + LIR_Assembler::exception_handler_size + - LIR_Assembler::deopt_handler_size); + 2 * LIR_Assembler::deopt_handler_size); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -878,15 +878,12 @@ case T_OBJECT : { ciObject* obj = con.as_object(); - if (obj->is_klass()) { - ciKlass* klass = obj->as_klass(); - if (!klass->is_loaded() || PatchALot) { - patch_state = state()->copy(); - t = new ObjectConstant(obj); - } else { - t = new InstanceConstant(klass->java_mirror()); - } + if (!obj->is_loaded() + || (PatchALot && obj->klass() != ciEnv::current()->String_klass())) { + patch_state = state()->copy(); + t = new ObjectConstant(obj); } else { + assert(!obj->is_klass(), "must be java_mirror of klass"); t = new InstanceConstant(obj->as_instance()); } break; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/c1/c1_Runtime1.cpp --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -601,7 +601,7 @@ static klassOop resolve_field_return_klass(methodHandle caller, int bci, TRAPS) { - Bytecode_field* field_access = Bytecode_field_at(caller(), caller->bcp_from(bci)); + Bytecode_field* field_access = Bytecode_field_at(caller, bci); // This can be static or non-static field access Bytecodes::Code code = field_access->code(); @@ -721,7 +721,7 @@ Handle load_klass(THREAD, NULL); // oop needed by load_klass_patching code if (stub_id == Runtime1::access_field_patching_id) { - Bytecode_field* field_access = Bytecode_field_at(caller_method(), caller_method->bcp_from(bci)); + Bytecode_field* field_access = Bytecode_field_at(caller_method, bci); FieldAccessInfo result; // initialize class if needed Bytecodes::Code code = field_access->code(); constantPoolHandle constants(THREAD, caller_method->constants()); @@ -781,11 +781,9 @@ case Bytecodes::_ldc: case Bytecodes::_ldc_w: { - Bytecode_loadconstant* cc = Bytecode_loadconstant_at(caller_method(), - caller_method->bcp_from(bci)); - klassOop resolved = caller_method->constants()->klass_at(cc->index(), CHECK); - // ldc wants the java mirror. - k = resolved->klass_part()->java_mirror(); + Bytecode_loadconstant* cc = Bytecode_loadconstant_at(caller_method, bci); + k = cc->resolve_constant(CHECK); + assert(k != NULL && !k->is_klass(), "must be class mirror or other Java constant"); } break; default: Unimplemented(); @@ -816,6 +814,15 @@ // Return to the now deoptimized frame. } + // If we are patching in a non-perm oop, make sure the nmethod + // is on the right list. + if (ScavengeRootsInCode && load_klass.not_null() && load_klass->is_scavengable()) { + MutexLockerEx ml_code (CodeCache_lock, Mutex::_no_safepoint_check_flag); + nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); + guarantee(nm != NULL, "only nmethods can contain non-perm oops"); + if (!nm->on_scavenge_root_list()) + CodeCache::add_scavenge_root_nmethod(nm); + } // Now copy code back @@ -1115,7 +1122,7 @@ if (length == 0) return; // Not guaranteed to be word atomic, but that doesn't matter // for anything but an oop array, which is covered by oop_arraycopy. - Copy::conjoint_bytes(src, dst, length); + Copy::conjoint_jbytes(src, dst, length); JRT_END JRT_LEAF(void, Runtime1::oop_arraycopy(HeapWord* src, HeapWord* dst, int num)) diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -106,7 +106,7 @@ void BCEscapeAnalyzer::set_returned(ArgumentMap vars) { for (int i = 0; i < _arg_size; i++) { if (vars.contains(i)) - _arg_returned.set_bit(i); + _arg_returned.set(i); } _return_local = _return_local && !(vars.contains_unknown() || vars.contains_allocated()); _return_allocated = _return_allocated && vars.contains_allocated() && !(vars.contains_unknown() || vars.contains_vars()); @@ -126,16 +126,16 @@ if (_conservative) return true; for (int i = 0; i < _arg_size; i++) { - if (vars.contains(i) && _arg_stack.at(i)) + if (vars.contains(i) && _arg_stack.test(i)) return true; } return false; } -void BCEscapeAnalyzer::clear_bits(ArgumentMap vars, BitMap &bm) { +void BCEscapeAnalyzer::clear_bits(ArgumentMap vars, VectorSet &bm) { for (int i = 0; i < _arg_size; i++) { if (vars.contains(i)) { - bm.clear_bit(i); + bm >>= i; } } } @@ -1157,15 +1157,15 @@ ciSignature* sig = method()->signature(); int j = 0; if (!method()->is_static()) { - _arg_local.set_bit(0); - _arg_stack.set_bit(0); + _arg_local.set(0); + _arg_stack.set(0); j++; } for (i = 0; i < sig->count(); i++) { ciType* t = sig->type_at(i); if (!t->is_primitive_type()) { - _arg_local.set_bit(j); - _arg_stack.set_bit(j); + _arg_local.set(j); + _arg_stack.set(j); } j += t->size(); } @@ -1198,9 +1198,9 @@ set_modified(var, OFFSET_ANY, 4); set_global_escape(var); } - _arg_local.clear(); - _arg_stack.clear(); - _arg_returned.clear(); + _arg_local.Clear(); + _arg_stack.Clear(); + _arg_returned.Clear(); _return_local = false; _return_allocated = false; _allocated_escapes = true; @@ -1254,7 +1254,7 @@ // Do not scan method if it has no object parameters and // does not returns an object (_return_allocated is set in initialize()). - if (_arg_local.is_empty() && !_return_allocated) { + if (_arg_local.Size() == 0 && !_return_allocated) { // Clear all info since method's bytecode was not analysed and // set pessimistic escape information. clear_escape_info(); @@ -1275,14 +1275,14 @@ // if (!has_dependencies() && !methodData()->is_empty()) { for (i = 0; i < _arg_size; i++) { - if (_arg_local.at(i)) { - assert(_arg_stack.at(i), "inconsistent escape info"); + if (_arg_local.test(i)) { + assert(_arg_stack.test(i), "inconsistent escape info"); methodData()->set_arg_local(i); methodData()->set_arg_stack(i); - } else if (_arg_stack.at(i)) { + } else if (_arg_stack.test(i)) { methodData()->set_arg_stack(i); } - if (_arg_returned.at(i)) { + if (_arg_returned.test(i)) { methodData()->set_arg_returned(i); } methodData()->set_arg_modified(i, _arg_modified[i]); @@ -1308,9 +1308,12 @@ // read escape information from method descriptor for (int i = 0; i < _arg_size; i++) { - _arg_local.at_put(i, methodData()->is_arg_local(i)); - _arg_stack.at_put(i, methodData()->is_arg_stack(i)); - _arg_returned.at_put(i, methodData()->is_arg_returned(i)); + if (methodData()->is_arg_local(i)) + _arg_local.set(i); + if (methodData()->is_arg_stack(i)) + _arg_stack.set(i); + if (methodData()->is_arg_returned(i)) + _arg_returned.set(i); _arg_modified[i] = methodData()->arg_modified(i); } _return_local = methodData()->eflag_set(methodDataOopDesc::return_local); @@ -1358,26 +1361,26 @@ BCEscapeAnalyzer::BCEscapeAnalyzer(ciMethod* method, BCEscapeAnalyzer* parent) : _conservative(method == NULL || !EstimateArgEscape) + , _arena(CURRENT_ENV->arena()) , _method(method) , _methodData(method ? method->method_data() : NULL) , _arg_size(method ? method->arg_size() : 0) - , _stack() - , _arg_local(_arg_size) - , _arg_stack(_arg_size) - , _arg_returned(_arg_size) - , _dirty(_arg_size) + , _arg_local(_arena) + , _arg_stack(_arena) + , _arg_returned(_arena) + , _dirty(_arena) , _return_local(false) , _return_allocated(false) , _allocated_escapes(false) , _unknown_modified(false) - , _dependencies() + , _dependencies(_arena, 4, 0, NULL) , _parent(parent) , _level(parent == NULL ? 0 : parent->level() + 1) { if (!_conservative) { - _arg_local.clear(); - _arg_stack.clear(); - _arg_returned.clear(); - _dirty.clear(); + _arg_local.Clear(); + _arg_stack.Clear(); + _arg_returned.Clear(); + _dirty.Clear(); Arena* arena = CURRENT_ENV->arena(); _arg_modified = (uint *) arena->Amalloc(_arg_size * sizeof(uint)); Copy::zero_to_bytes(_arg_modified, _arg_size * sizeof(uint)); @@ -1414,8 +1417,8 @@ deps->assert_evol_method(method()); } for (int i = 0; i < _dependencies.length(); i+=2) { - ciKlass *k = _dependencies[i]->as_klass(); - ciMethod *m = _dependencies[i+1]->as_method(); + ciKlass *k = _dependencies.at(i)->as_klass(); + ciMethod *m = _dependencies.at(i+1)->as_method(); deps->assert_unique_concrete_method(k, m); } } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -22,9 +22,6 @@ * */ -define_array(ciObjectArray, ciObject*); -define_stack(ciObjectList, ciObjectArray); - // This class implements a fast, conservative analysis of effect of methods // on the escape state of their arguments. The analysis is at the bytecode // level. @@ -34,18 +31,17 @@ class BCEscapeAnalyzer : public ResourceObj { private: + Arena* _arena; // ciEnv arena + bool _conservative; // If true, return maximally // conservative results. ciMethod* _method; ciMethodData* _methodData; int _arg_size; - - intStack _stack; - - BitMap _arg_local; - BitMap _arg_stack; - BitMap _arg_returned; - BitMap _dirty; + VectorSet _arg_local; + VectorSet _arg_stack; + VectorSet _arg_returned; + VectorSet _dirty; enum{ ARG_OFFSET_MAX = 31}; uint *_arg_modified; @@ -54,7 +50,7 @@ bool _allocated_escapes; bool _unknown_modified; - ciObjectList _dependencies; + GrowableArray _dependencies; ciMethodBlocks *_methodBlocks; @@ -68,20 +64,10 @@ private: // helper functions bool is_argument(int i) { return i >= 0 && i < _arg_size; } - - void raw_push(int i) { _stack.push(i); } - int raw_pop() { return _stack.is_empty() ? -1 : _stack.pop(); } - void apush(int i) { raw_push(i); } - void spush() { raw_push(-1); } - void lpush() { spush(); spush(); } - int apop() { return raw_pop(); } - void spop() { assert(_stack.is_empty() || _stack.top() == -1, ""); raw_pop(); } - void lpop() { spop(); spop(); } - void set_returned(ArgumentMap vars); bool is_argument(ArgumentMap vars); bool is_arg_stack(ArgumentMap vars); - void clear_bits(ArgumentMap vars, BitMap &bs); + void clear_bits(ArgumentMap vars, VectorSet &bs); void set_method_escape(ArgumentMap vars); void set_global_escape(ArgumentMap vars); void set_dirty(ArgumentMap vars); @@ -116,25 +102,25 @@ ciMethodData* methodData() const { return _methodData; } BCEscapeAnalyzer* parent() const { return _parent; } int level() const { return _level; } - ciObjectList* dependencies() { return &_dependencies; } + GrowableArray* dependencies() { return &_dependencies; } bool has_dependencies() const { return !_dependencies.is_empty(); } // retrieval of interprocedural escape information // The given argument does not escape the callee. bool is_arg_local(int i) const { - return !_conservative && _arg_local.at(i); + return !_conservative && _arg_local.test(i); } // The given argument escapes the callee, but does not become globally // reachable. bool is_arg_stack(int i) const { - return !_conservative && _arg_stack.at(i); + return !_conservative && _arg_stack.test(i); } // The given argument does not escape globally, and may be returned. bool is_arg_returned(int i) const { - return !_conservative && _arg_returned.at(i); } + return !_conservative && _arg_returned.test(i); } // True iff only input arguments are returned. bool is_return_local() const { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciCPCache.cpp --- a/hotspot/src/share/vm/ci/ciCPCache.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciCPCache.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -44,13 +44,23 @@ // ciCPCache::is_f1_null_at bool ciCPCache::is_f1_null_at(int index) { VM_ENTRY_MARK; - constantPoolCacheOop cpcache = (constantPoolCacheOop) get_oop(); - oop f1 = cpcache->secondary_entry_at(index)->f1(); + oop f1 = entry_at(index)->f1(); return (f1 == NULL); } // ------------------------------------------------------------------ +// ciCPCache::get_pool_index +int ciCPCache::get_pool_index(int index) { + VM_ENTRY_MARK; + ConstantPoolCacheEntry* e = entry_at(index); + if (e->is_secondary_entry()) + e = entry_at(e->main_entry_index()); + return e->constant_pool_index(); +} + + +// ------------------------------------------------------------------ // ciCPCache::print // // Print debugging information about the cache. diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciCPCache.hpp --- a/hotspot/src/share/vm/ci/ciCPCache.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciCPCache.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -29,6 +29,18 @@ // Note: This class is called ciCPCache as ciConstantPoolCache is used // for something different. class ciCPCache : public ciObject { +private: + constantPoolCacheOop get_cpCacheOop() { // must be called inside a VM_ENTRY_MARK + return (constantPoolCacheOop) get_oop(); + } + + ConstantPoolCacheEntry* entry_at(int i) { + int raw_index = i; + if (constantPoolCacheOopDesc::is_secondary_index(i)) + raw_index = constantPoolCacheOopDesc::decode_secondary_index(i); + return get_cpCacheOop()->entry_at(raw_index); + } + public: ciCPCache(constantPoolCacheHandle cpcache) : ciObject(cpcache) {} @@ -41,5 +53,7 @@ bool is_f1_null_at(int index); + int get_pool_index(int index); + void print(); }; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciClassList.hpp --- a/hotspot/src/share/vm/ci/ciClassList.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciClassList.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -85,6 +85,7 @@ friend class ciConstantPoolCache; \ friend class ciField; \ friend class ciConstant; \ +friend class ciCPCache; \ friend class ciFlags; \ friend class ciExceptionHandler; \ friend class ciCallProfile; \ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciEnv.cpp --- a/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -511,9 +511,22 @@ // // Implementation of get_constant_by_index(). ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool, - int index, + int pool_index, int cache_index, ciInstanceKlass* accessor) { + bool ignore_will_link; EXCEPTION_CONTEXT; + int index = pool_index; + if (cache_index >= 0) { + assert(index < 0, "only one kind of index at a time"); + ConstantPoolCacheEntry* cpc_entry = cpool->cache()->entry_at(cache_index); + index = cpc_entry->constant_pool_index(); + oop obj = cpc_entry->f1(); + if (obj != NULL) { + assert(obj->is_instance(), "must be an instance"); + ciObject* ciobj = get_object(obj); + return ciConstant(T_OBJECT, ciobj); + } + } constantTag tag = cpool->tag_at(index); if (tag.is_int()) { return ciConstant(T_INT, (jint)cpool->int_at(index)); @@ -540,8 +553,7 @@ return ciConstant(T_OBJECT, constant); } else if (tag.is_klass() || tag.is_unresolved_klass()) { // 4881222: allow ldc to take a class type - bool ignore; - ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore, accessor); + ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; record_out_of_memory_failure(); @@ -549,12 +561,26 @@ } assert (klass->is_instance_klass() || klass->is_array_klass(), "must be an instance or array klass "); - return ciConstant(T_OBJECT, klass); + return ciConstant(T_OBJECT, klass->java_mirror()); } else if (tag.is_object()) { oop obj = cpool->object_at(index); assert(obj->is_instance(), "must be an instance"); ciObject* ciobj = get_object(obj); return ciConstant(T_OBJECT, ciobj); + } else if (tag.is_method_type()) { + // must execute Java code to link this CP entry into cache[i].f1 + ciSymbol* signature = get_object(cpool->method_type_signature_at(index))->as_symbol(); + ciObject* ciobj = get_unloaded_method_type_constant(signature); + return ciConstant(T_OBJECT, ciobj); + } else if (tag.is_method_handle()) { + // must execute Java code to link this CP entry into cache[i].f1 + int ref_kind = cpool->method_handle_ref_kind_at(index); + int callee_index = cpool->method_handle_klass_index_at(index); + ciKlass* callee = get_klass_by_index_impl(cpool, callee_index, ignore_will_link, accessor); + ciSymbol* name = get_object(cpool->method_handle_name_ref_at(index))->as_symbol(); + ciSymbol* signature = get_object(cpool->method_handle_signature_ref_at(index))->as_symbol(); + ciObject* ciobj = get_unloaded_method_handle_constant(callee, name, signature, ref_kind); + return ciConstant(T_OBJECT, ciobj); } else { ShouldNotReachHere(); return ciConstant(); @@ -562,61 +588,15 @@ } // ------------------------------------------------------------------ -// ciEnv::is_unresolved_string_impl -// -// Implementation of is_unresolved_string(). -bool ciEnv::is_unresolved_string_impl(instanceKlass* accessor, int index) const { - EXCEPTION_CONTEXT; - assert(accessor->is_linked(), "must be linked before accessing constant pool"); - constantPoolOop cpool = accessor->constants(); - constantTag tag = cpool->tag_at(index); - return tag.is_unresolved_string(); -} - -// ------------------------------------------------------------------ -// ciEnv::is_unresolved_klass_impl -// -// Implementation of is_unresolved_klass(). -bool ciEnv::is_unresolved_klass_impl(instanceKlass* accessor, int index) const { - EXCEPTION_CONTEXT; - assert(accessor->is_linked(), "must be linked before accessing constant pool"); - constantPoolOop cpool = accessor->constants(); - constantTag tag = cpool->tag_at(index); - return tag.is_unresolved_klass(); -} - -// ------------------------------------------------------------------ // ciEnv::get_constant_by_index // // Pull a constant out of the constant pool. How appropriate. // // Implementation note: this query is currently in no way cached. ciConstant ciEnv::get_constant_by_index(constantPoolHandle cpool, - int index, + int pool_index, int cache_index, ciInstanceKlass* accessor) { - GUARDED_VM_ENTRY(return get_constant_by_index_impl(cpool, index, accessor);) -} - -// ------------------------------------------------------------------ -// ciEnv::is_unresolved_string -// -// Check constant pool -// -// Implementation note: this query is currently in no way cached. -bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor, - int index) const { - GUARDED_VM_ENTRY(return is_unresolved_string_impl(accessor->get_instanceKlass(), index); ) -} - -// ------------------------------------------------------------------ -// ciEnv::is_unresolved_klass -// -// Check constant pool -// -// Implementation note: this query is currently in no way cached. -bool ciEnv::is_unresolved_klass(ciInstanceKlass* accessor, - int index) const { - GUARDED_VM_ENTRY(return is_unresolved_klass_impl(accessor->get_instanceKlass(), index); ) + GUARDED_VM_ENTRY(return get_constant_by_index_impl(cpool, pool_index, cache_index, accessor);) } // ------------------------------------------------------------------ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciEnv.hpp --- a/hotspot/src/share/vm/ci/ciEnv.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciEnv.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -116,12 +116,8 @@ bool& is_accessible, ciInstanceKlass* loading_klass); ciConstant get_constant_by_index(constantPoolHandle cpool, - int constant_index, + int pool_index, int cache_index, ciInstanceKlass* accessor); - bool is_unresolved_string(ciInstanceKlass* loading_klass, - int constant_index) const; - bool is_unresolved_klass(ciInstanceKlass* loading_klass, - int constant_index) const; ciField* get_field_by_index(ciInstanceKlass* loading_klass, int field_index); ciMethod* get_method_by_index(constantPoolHandle cpool, @@ -137,12 +133,8 @@ bool& is_accessible, ciInstanceKlass* loading_klass); ciConstant get_constant_by_index_impl(constantPoolHandle cpool, - int constant_index, + int pool_index, int cache_index, ciInstanceKlass* loading_klass); - bool is_unresolved_string_impl (instanceKlass* loading_klass, - int constant_index) const; - bool is_unresolved_klass_impl (instanceKlass* loading_klass, - int constant_index) const; ciField* get_field_by_index_impl(ciInstanceKlass* loading_klass, int field_index); ciMethod* get_method_by_index_impl(constantPoolHandle cpool, @@ -190,6 +182,25 @@ return _factory->get_unloaded_klass(accessing_klass, name, true); } + // Get a ciKlass representing an unloaded klass mirror. + // Result is not necessarily unique, but will be unloaded. + ciInstance* get_unloaded_klass_mirror(ciKlass* type) { + return _factory->get_unloaded_klass_mirror(type); + } + + // Get a ciInstance representing an unresolved method handle constant. + ciInstance* get_unloaded_method_handle_constant(ciKlass* holder, + ciSymbol* name, + ciSymbol* signature, + int ref_kind) { + return _factory->get_unloaded_method_handle_constant(holder, name, signature, ref_kind); + } + + // Get a ciInstance representing an unresolved method type constant. + ciInstance* get_unloaded_method_type_constant(ciSymbol* signature) { + return _factory->get_unloaded_method_type_constant(signature); + } + // See if we already have an unloaded klass for the given name // or return NULL if not. ciKlass *check_get_unloaded_klass(ciKlass* accessing_klass, ciSymbol* name) { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciInstanceKlass.cpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,9 +44,7 @@ _flags = ciFlags(access_flags); _has_finalizer = access_flags.has_finalizer(); _has_subklass = ik->subklass() != NULL; - _is_initialized = ik->is_initialized(); - // Next line must follow and use the result of the previous line: - _is_linked = _is_initialized || ik->is_linked(); + _init_state = (instanceKlass::ClassState)ik->get_init_state(); _nonstatic_field_size = ik->nonstatic_field_size(); _has_nonstatic_fields = ik->has_nonstatic_fields(); _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields: @@ -91,8 +89,7 @@ : ciKlass(name, ciInstanceKlassKlass::make()) { assert(name->byte_at(0) != '[', "not an instance klass"); - _is_initialized = false; - _is_linked = false; + _init_state = (instanceKlass::ClassState)0; _nonstatic_field_size = -1; _has_nonstatic_fields = false; _nonstatic_fields = NULL; @@ -109,21 +106,10 @@ // ------------------------------------------------------------------ // ciInstanceKlass::compute_shared_is_initialized -bool ciInstanceKlass::compute_shared_is_initialized() { +void ciInstanceKlass::compute_shared_init_state() { GUARDED_VM_ENTRY( instanceKlass* ik = get_instanceKlass(); - _is_initialized = ik->is_initialized(); - return _is_initialized; - ) -} - -// ------------------------------------------------------------------ -// ciInstanceKlass::compute_shared_is_linked -bool ciInstanceKlass::compute_shared_is_linked() { - GUARDED_VM_ENTRY( - instanceKlass* ik = get_instanceKlass(); - _is_linked = ik->is_linked(); - return _is_linked; + _init_state = (instanceKlass::ClassState)ik->get_init_state(); ) } @@ -323,8 +309,8 @@ // ciInstanceKlass::java_mirror // // Get the instance of java.lang.Class corresponding to this klass. +// Cache it on this->_java_mirror. ciInstance* ciInstanceKlass::java_mirror() { - assert(is_loaded(), "must be loaded"); if (_java_mirror == NULL) { _java_mirror = ciKlass::java_mirror(); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciInstanceKlass.hpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,9 +39,8 @@ jobject _loader; jobject _protection_domain; + instanceKlass::ClassState _init_state; // state of class bool _is_shared; - bool _is_initialized; - bool _is_linked; bool _has_finalizer; bool _has_subklass; bool _has_nonstatic_fields; @@ -87,27 +86,34 @@ bool is_shared() { return _is_shared; } - bool compute_shared_is_initialized(); - bool compute_shared_is_linked(); + void compute_shared_init_state(); bool compute_shared_has_subklass(); int compute_shared_nof_implementors(); int compute_nonstatic_fields(); GrowableArray* compute_nonstatic_fields_impl(GrowableArray* super_fields); + // Update the init_state for shared klasses + void update_if_shared(instanceKlass::ClassState expected) { + if (_is_shared && _init_state != expected) { + if (is_loaded()) compute_shared_init_state(); + } + } + public: // Has this klass been initialized? bool is_initialized() { - if (_is_shared && !_is_initialized) { - return is_loaded() && compute_shared_is_initialized(); - } - return _is_initialized; + update_if_shared(instanceKlass::fully_initialized); + return _init_state == instanceKlass::fully_initialized; + } + // Is this klass being initialized? + bool is_being_initialized() { + update_if_shared(instanceKlass::being_initialized); + return _init_state == instanceKlass::being_initialized; } // Has this klass been linked? bool is_linked() { - if (_is_shared && !_is_linked) { - return is_loaded() && compute_shared_is_linked(); - } - return _is_linked; + update_if_shared(instanceKlass::linked); + return _init_state >= instanceKlass::linked; } // General klass information. diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciKlass.cpp --- a/hotspot/src/share/vm/ci/ciKlass.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciKlass.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -192,8 +192,14 @@ // ------------------------------------------------------------------ // ciKlass::java_mirror +// +// Get the instance of java.lang.Class corresponding to this klass. +// If it is an unloaded instance or array klass, return an unloaded +// mirror object of type Class. ciInstance* ciKlass::java_mirror() { GUARDED_VM_ENTRY( + if (!is_loaded()) + return ciEnv::current()->get_unloaded_klass_mirror(this); oop java_mirror = get_Klass()->java_mirror(); return CURRENT_ENV->get_object(java_mirror)->as_instance(); ) diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -54,10 +54,10 @@ _code = NULL; _exception_handlers = NULL; _liveness = NULL; - _bcea = NULL; _method_blocks = NULL; #ifdef COMPILER2 _flow = NULL; + _bcea = NULL; #endif // COMPILER2 ciEnv *env = CURRENT_ENV; @@ -121,11 +121,11 @@ _intrinsic_id = vmIntrinsics::_none; _liveness = NULL; _can_be_statically_bound = false; - _bcea = NULL; _method_blocks = NULL; _method_data = NULL; #ifdef COMPILER2 _flow = NULL; + _bcea = NULL; #endif // COMPILER2 } @@ -1033,10 +1033,15 @@ bool ciMethod::is_initializer () const { FETCH_FLAG_FROM_VM(is_initializer); } BCEscapeAnalyzer *ciMethod::get_bcea() { +#ifdef COMPILER2 if (_bcea == NULL) { _bcea = new (CURRENT_ENV->arena()) BCEscapeAnalyzer(this, NULL); } return _bcea; +#else // COMPILER2 + ShouldNotReachHere(); + return NULL; +#endif // COMPILER2 } ciMethodBlocks *ciMethod::get_method_blocks() { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciMethod.hpp --- a/hotspot/src/share/vm/ci/ciMethod.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -48,7 +48,6 @@ ciInstanceKlass* _holder; ciSignature* _signature; ciMethodData* _method_data; - BCEscapeAnalyzer* _bcea; ciMethodBlocks* _method_blocks; // Code attributes. @@ -72,7 +71,8 @@ // Optional liveness analyzer. MethodLiveness* _liveness; #ifdef COMPILER2 - ciTypeFlow* _flow; + ciTypeFlow* _flow; + BCEscapeAnalyzer* _bcea; #endif ciMethod(methodHandle h_m); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciObjectFactory.cpp --- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -70,6 +70,7 @@ _unloaded_methods = new (arena) GrowableArray(arena, 4, 0, NULL); _unloaded_klasses = new (arena) GrowableArray(arena, 8, 0, NULL); + _unloaded_instances = new (arena) GrowableArray(arena, 4, 0, NULL); _return_addresses = new (arena) GrowableArray(arena, 8, 0, NULL); } @@ -443,6 +444,74 @@ return new_klass; } + +//------------------------------------------------------------------ +// ciObjectFactory::get_unloaded_instance +// +// Get a ciInstance representing an as-yet undetermined instance of a given class. +// +ciInstance* ciObjectFactory::get_unloaded_instance(ciInstanceKlass* instance_klass) { + for (int i=0; i<_unloaded_instances->length(); i++) { + ciInstance* entry = _unloaded_instances->at(i); + if (entry->klass()->equals(instance_klass)) { + // We've found a match. + return entry; + } + } + + // This is a new unloaded instance. Create it and stick it in + // the cache. + ciInstance* new_instance = new (arena()) ciInstance(instance_klass); + + init_ident_of(new_instance); + _unloaded_instances->append(new_instance); + + // make sure it looks the way we want: + assert(!new_instance->is_loaded(), ""); + assert(new_instance->klass() == instance_klass, ""); + + return new_instance; +} + + +//------------------------------------------------------------------ +// ciObjectFactory::get_unloaded_klass_mirror +// +// Get a ciInstance representing an unresolved klass mirror. +// +// Currently, this ignores the parameters and returns a unique unloaded instance. +ciInstance* ciObjectFactory::get_unloaded_klass_mirror(ciKlass* type) { + assert(ciEnv::_Class_klass != NULL, ""); + return get_unloaded_instance(ciEnv::_Class_klass->as_instance_klass()); +} + +//------------------------------------------------------------------ +// ciObjectFactory::get_unloaded_method_handle_constant +// +// Get a ciInstance representing an unresolved method handle constant. +// +// Currently, this ignores the parameters and returns a unique unloaded instance. +ciInstance* ciObjectFactory::get_unloaded_method_handle_constant(ciKlass* holder, + ciSymbol* name, + ciSymbol* signature, + int ref_kind) { + if (ciEnv::_MethodHandle_klass == NULL) return NULL; + return get_unloaded_instance(ciEnv::_MethodHandle_klass->as_instance_klass()); +} + +//------------------------------------------------------------------ +// ciObjectFactory::get_unloaded_method_type_constant +// +// Get a ciInstance representing an unresolved method type constant. +// +// Currently, this ignores the parameters and returns a unique unloaded instance. +ciInstance* ciObjectFactory::get_unloaded_method_type_constant(ciSymbol* signature) { + if (ciEnv::_MethodType_klass == NULL) return NULL; + return get_unloaded_instance(ciEnv::_MethodType_klass->as_instance_klass()); +} + + + //------------------------------------------------------------------ // ciObjectFactory::get_empty_methodData // @@ -637,7 +706,8 @@ // // Print debugging information about the object factory void ciObjectFactory::print() { - tty->print("", + tty->print("", _ci_objects->length(), _unloaded_methods->length(), + _unloaded_instances->length(), _unloaded_klasses->length()); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciObjectFactory.hpp --- a/hotspot/src/share/vm/ci/ciObjectFactory.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciObjectFactory.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -39,6 +39,7 @@ GrowableArray* _ci_objects; GrowableArray* _unloaded_methods; GrowableArray* _unloaded_klasses; + GrowableArray* _unloaded_instances; GrowableArray* _return_addresses; int _next_ident; @@ -73,6 +74,8 @@ void print_contents_impl(); + ciInstance* get_unloaded_instance(ciInstanceKlass* klass); + public: static bool is_initialized() { return _initialized; } @@ -98,6 +101,18 @@ ciSymbol* name, bool create_if_not_found); + // Get a ciInstance representing an unresolved klass mirror. + ciInstance* get_unloaded_klass_mirror(ciKlass* type); + + // Get a ciInstance representing an unresolved method handle constant. + ciInstance* get_unloaded_method_handle_constant(ciKlass* holder, + ciSymbol* name, + ciSymbol* signature, + int ref_kind); + + // Get a ciInstance representing an unresolved method type constant. + ciInstance* get_unloaded_method_type_constant(ciSymbol* signature); + // Get the ciMethodData representing the methodData for a method // with none. diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciStreams.cpp --- a/hotspot/src/share/vm/ci/ciStreams.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciStreams.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -186,12 +186,13 @@ } // ------------------------------------------------------------------ -// ciBytecodeStream::get_constant_index +// ciBytecodeStream::get_constant_raw_index // // If this bytecode is one of the ldc variants, get the index of the // referenced constant. -int ciBytecodeStream::get_constant_index() const { - switch(cur_bc()) { +int ciBytecodeStream::get_constant_raw_index() const { + // work-alike for Bytecode_loadconstant::raw_index() + switch (cur_bc()) { case Bytecodes::_ldc: return get_index_u1(); case Bytecodes::_ldc_w: @@ -202,25 +203,52 @@ return 0; } } + +// ------------------------------------------------------------------ +// ciBytecodeStream::get_constant_pool_index +// Decode any CP cache index into a regular pool index. +int ciBytecodeStream::get_constant_pool_index() const { + // work-alike for Bytecode_loadconstant::pool_index() + int index = get_constant_raw_index(); + if (has_cache_index()) { + return get_cpcache()->get_pool_index(index); + } + return index; +} + +// ------------------------------------------------------------------ +// ciBytecodeStream::get_constant_cache_index +// Return the CP cache index, or -1 if there isn't any. +int ciBytecodeStream::get_constant_cache_index() const { + // work-alike for Bytecode_loadconstant::cache_index() + return has_cache_index() ? get_constant_raw_index() : -1; +} + // ------------------------------------------------------------------ // ciBytecodeStream::get_constant // // If this bytecode is one of the ldc variants, get the referenced // constant. ciConstant ciBytecodeStream::get_constant() { + int pool_index = get_constant_raw_index(); + int cache_index = -1; + if (has_cache_index()) { + cache_index = pool_index; + pool_index = -1; + } VM_ENTRY_MARK; constantPoolHandle cpool(_method->get_methodOop()->constants()); - return CURRENT_ENV->get_constant_by_index(cpool, get_constant_index(), _holder); + return CURRENT_ENV->get_constant_by_index(cpool, pool_index, cache_index, _holder); } // ------------------------------------------------------------------ -bool ciBytecodeStream::is_unresolved_string() const { - return CURRENT_ENV->is_unresolved_string(_holder, get_constant_index()); -} - -// ------------------------------------------------------------------ -bool ciBytecodeStream::is_unresolved_klass() const { - return CURRENT_ENV->is_unresolved_klass(_holder, get_klass_index()); +// ciBytecodeStream::get_constant_pool_tag +// +// If this bytecode is one of the ldc variants, get the referenced +// constant. +constantTag ciBytecodeStream::get_constant_pool_tag(int index) const { + VM_ENTRY_MARK; + return _method->get_methodOop()->constants()->tag_at(index); } // ------------------------------------------------------------------ @@ -378,13 +406,16 @@ // ------------------------------------------------------------------ // ciBytecodeStream::get_cpcache -ciCPCache* ciBytecodeStream::get_cpcache() { - VM_ENTRY_MARK; - // Get the constant pool. - constantPoolOop cpool = _holder->get_instanceKlass()->constants(); - constantPoolCacheOop cpcache = cpool->cache(); +ciCPCache* ciBytecodeStream::get_cpcache() const { + if (_cpcache == NULL) { + VM_ENTRY_MARK; + // Get the constant pool. + constantPoolOop cpool = _holder->get_instanceKlass()->constants(); + constantPoolCacheOop cpcache = cpool->cache(); - return CURRENT_ENV->get_object(cpcache)->as_cpcache(); + *(ciCPCache**)&_cpcache = CURRENT_ENV->get_object(cpcache)->as_cpcache(); + } + return _cpcache; } // ------------------------------------------------------------------ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciStreams.hpp --- a/hotspot/src/share/vm/ci/ciStreams.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciStreams.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -46,6 +46,7 @@ ciMethod* _method; // the method ciInstanceKlass* _holder; + ciCPCache* _cpcache; address _bc_start; // Start of current bytecode for table address _was_wide; // Address past last wide bytecode jint* _table_base; // Aligned start of last table or switch @@ -58,7 +59,9 @@ void reset( address base, unsigned int size ) { _bc_start =_was_wide = 0; - _start = _pc = base; _end = base + size; } + _start = _pc = base; _end = base + size; + _cpcache = NULL; + } void assert_wide(bool require_wide) const { if (require_wide) @@ -136,15 +139,20 @@ bool is_wide() const { return ( _pc == _was_wide ); } // Does this instruction contain an index which refes into the CP cache? - bool uses_cp_cache() const { return Bytecodes::uses_cp_cache(cur_bc_raw()); } + bool has_cache_index() const { return Bytecodes::uses_cp_cache(cur_bc_raw()); } int get_index_u1() const { return bytecode()->get_index_u1(cur_bc_raw()); } + int get_index_u1_cpcache() const { + return bytecode()->get_index_u1_cpcache(cur_bc_raw()); + } + // Get a byte index following this bytecode. // If prefixed with a wide bytecode, get a wide index. int get_index() const { + assert(!has_cache_index(), "else use cpcache variant"); return (_pc == _was_wide) // was widened? ? get_index_u2(true) // yes, return wide index : get_index_u1(); // no, return narrow index @@ -207,7 +215,9 @@ return cur_bci() + get_int_table(index); } // --- Constant pool access --- - int get_constant_index() const; + int get_constant_raw_index() const; + int get_constant_pool_index() const; + int get_constant_cache_index() const; int get_field_index(); int get_method_index(); @@ -217,12 +227,17 @@ int get_klass_index() const; // If this bytecode is one of the ldc variants, get the referenced - // constant + // constant. Do not attempt to resolve it, since that would require + // execution of Java code. If it is not resolved, return an unloaded + // object (ciConstant.as_object()->is_loaded() == false). ciConstant get_constant(); - // True if the ldc variant points to an unresolved string - bool is_unresolved_string() const; - // True if the ldc variant points to an unresolved klass - bool is_unresolved_klass() const; + constantTag get_constant_pool_tag(int index) const; + + // True if the klass-using bytecode points to an unresolved klass + bool is_unresolved_klass() const { + constantTag tag = get_constant_pool_tag(get_klass_index()); + return tag.is_unresolved_klass(); + } // If this bytecode is one of get_field, get_static, put_field, // or put_static, get the referenced field. @@ -238,7 +253,7 @@ int get_method_holder_index(); int get_method_signature_index(); - ciCPCache* get_cpcache(); + ciCPCache* get_cpcache() const; ciCallSite* get_call_site(); }; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/ci/ciTypeFlow.cpp --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -712,10 +712,8 @@ ciObject* obj = con.as_object(); if (obj->is_null_object()) { push_null(); - } else if (obj->is_klass()) { - // The type of ldc is java.lang.Class - push_object(outer()->env()->Class_klass()); } else { + assert(!obj->is_klass(), "must be java_mirror of klass"); push_object(obj->klass()); } } else { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -117,6 +117,29 @@ cp->string_index_at_put(index, string_index); } break; + case JVM_CONSTANT_MethodHandle : + case JVM_CONSTANT_MethodType : + if (!EnableMethodHandles || + _major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { + classfile_parse_error( + (!EnableInvokeDynamic ? + "This JVM does not support constant tag %u in class file %s" : + "Class file version does not support constant tag %u in class file %s"), + tag, CHECK); + } + if (tag == JVM_CONSTANT_MethodHandle) { + cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags + u1 ref_kind = cfs->get_u1_fast(); + u2 method_index = cfs->get_u2_fast(); + cp->method_handle_index_at_put(index, ref_kind, method_index); + } else if (tag == JVM_CONSTANT_MethodType) { + cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags + u2 signature_index = cfs->get_u2_fast(); + cp->method_type_index_at_put(index, signature_index); + } else { + ShouldNotReachHere(); + } + break; case JVM_CONSTANT_Integer : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags @@ -337,6 +360,60 @@ cp->unresolved_string_at_put(index, sym); } break; + case JVM_CONSTANT_MethodHandle : + { + int ref_index = cp->method_handle_index_at(index); + check_property( + valid_cp_range(ref_index, length) && + EnableMethodHandles, + "Invalid constant pool index %u in class file %s", + ref_index, CHECK_(nullHandle)); + constantTag tag = cp->tag_at(ref_index); + int ref_kind = cp->method_handle_ref_kind_at(index); + switch (ref_kind) { + case JVM_REF_getField: + case JVM_REF_getStatic: + case JVM_REF_putField: + case JVM_REF_putStatic: + check_property( + tag.is_field(), + "Invalid constant pool index %u in class file %s (not a field)", + ref_index, CHECK_(nullHandle)); + break; + case JVM_REF_invokeVirtual: + case JVM_REF_invokeStatic: + case JVM_REF_invokeSpecial: + case JVM_REF_newInvokeSpecial: + check_property( + tag.is_method(), + "Invalid constant pool index %u in class file %s (not a method)", + ref_index, CHECK_(nullHandle)); + break; + case JVM_REF_invokeInterface: + check_property( + tag.is_interface_method(), + "Invalid constant pool index %u in class file %s (not an interface method)", + ref_index, CHECK_(nullHandle)); + break; + default: + classfile_parse_error( + "Bad method handle kind at constant pool index %u in class file %s", + index, CHECK_(nullHandle)); + } + // Keep the ref_index unchanged. It will be indirected at link-time. + } + break; + case JVM_CONSTANT_MethodType : + { + int ref_index = cp->method_type_index_at(index); + check_property( + valid_cp_range(ref_index, length) && + cp->tag_at(ref_index).is_utf8() && + EnableMethodHandles, + "Invalid constant pool index %u in class file %s", + ref_index, CHECK_(nullHandle)); + } + break; default: fatal(err_msg("bad constant pool tag value %u", cp->tag_at(index).value())); @@ -452,6 +529,43 @@ } break; } + case JVM_CONSTANT_MethodHandle: { + int ref_index = cp->method_handle_index_at(index); + int ref_kind = cp->method_handle_ref_kind_at(index); + switch (ref_kind) { + case JVM_REF_invokeVirtual: + case JVM_REF_invokeStatic: + case JVM_REF_invokeSpecial: + case JVM_REF_newInvokeSpecial: + { + int name_and_type_ref_index = cp->name_and_type_ref_index_at(ref_index); + int name_ref_index = cp->name_ref_index_at(name_and_type_ref_index); + symbolHandle name(THREAD, cp->symbol_at(name_ref_index)); + if (ref_kind == JVM_REF_newInvokeSpecial) { + if (name() != vmSymbols::object_initializer_name()) { + classfile_parse_error( + "Bad constructor name at constant pool index %u in class file %s", + name_ref_index, CHECK_(nullHandle)); + } + } else { + if (name() == vmSymbols::object_initializer_name()) { + classfile_parse_error( + "Bad method name at constant pool index %u in class file %s", + name_ref_index, CHECK_(nullHandle)); + } + } + } + break; + // Other ref_kinds are already fully checked in previous pass. + } + break; + } + case JVM_CONSTANT_MethodType: { + symbolHandle no_name = vmSymbolHandles::type_name(); // place holder + symbolHandle signature(THREAD, cp->method_type_signature_at(index)); + verify_legal_method_signature(no_name, signature, CHECK_(nullHandle)); + break; + } } // end of switch } // end of for @@ -467,7 +581,7 @@ case JVM_CONSTANT_UnresolvedClass : // Patching a class means pre-resolving it. // The name in the constant pool is ignored. - if (patch->klass() == SystemDictionary::Class_klass()) { // %%% java_lang_Class::is_instance + if (java_lang_Class::is_instance(patch())) { guarantee_property(!java_lang_Class::is_primitive(patch()), "Illegal class patch at %d in class file %s", index, CHECK); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/classfile/classLoader.cpp --- a/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -832,7 +832,6 @@ instanceKlassHandle ClassLoader::load_classfile(symbolHandle h_name, TRAPS) { - VTuneClassLoadMarker clm; ResourceMark rm(THREAD); EventMark m("loading class " INTPTR_FORMAT, (address)h_name()); ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -2454,6 +2454,48 @@ return Handle(THREAD, (oop) result.get_jobject()); } +// Ask Java code to find or construct a method handle constant. +Handle SystemDictionary::link_method_handle_constant(KlassHandle caller, + int ref_kind, //e.g., JVM_REF_invokeVirtual + KlassHandle callee, + symbolHandle name_sym, + symbolHandle signature, + TRAPS) { + Handle empty; + Handle name = java_lang_String::create_from_symbol(name_sym(), CHECK_(empty)); + Handle type; + if (signature->utf8_length() > 0 && signature->byte_at(0) == '(') { + bool ignore_is_on_bcp = false; + type = find_method_handle_type(signature, caller, ignore_is_on_bcp, CHECK_(empty)); + } else { + SignatureStream ss(signature(), false); + if (!ss.is_done()) { + oop mirror = ss.as_java_mirror(caller->class_loader(), caller->protection_domain(), + SignatureStream::NCDFError, CHECK_(empty)); + type = Handle(THREAD, mirror); + ss.next(); + if (!ss.is_done()) type = Handle(); // error! + } + } + if (type.is_null()) { + THROW_MSG_(vmSymbols::java_lang_LinkageError(), "bad signature", empty); + } + + // call sun.dyn.MethodHandleNatives::linkMethodHandleConstant(Class caller, int refKind, Class callee, String name, Object type) -> MethodHandle + JavaCallArguments args; + args.push_oop(caller->java_mirror()); // the referring class + args.push_int(ref_kind); + args.push_oop(callee->java_mirror()); // the target class + args.push_oop(name()); + args.push_oop(type()); + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, + SystemDictionary::MethodHandleNatives_klass(), + vmSymbols::linkMethodHandleConstant_name(), + vmSymbols::linkMethodHandleConstant_signature(), + &args, CHECK_(empty)); + return Handle(THREAD, (oop) result.get_jobject()); +} // Ask Java code to find or construct a java.dyn.CallSite for the given // name and signature, as interpreted relative to the given class loader. diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -473,6 +473,13 @@ KlassHandle accessing_klass, bool& return_bcp_flag, TRAPS); + // ask Java to compute a java.dyn.MethodHandle object for a given CP entry + static Handle link_method_handle_constant(KlassHandle caller, + int ref_kind, //e.g., JVM_REF_invokeVirtual + KlassHandle callee, + symbolHandle name, + symbolHandle signature, + TRAPS); // ask Java to create a dynamic call site, while linking an invokedynamic op static Handle make_dynamic_call_site(Handle bootstrap_method, // Callee information: diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/classfile/verifier.cpp --- a/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1598,7 +1598,10 @@ if (opcode == Bytecodes::_ldc || opcode == Bytecodes::_ldc_w) { if (!tag.is_unresolved_string() && !tag.is_unresolved_klass()) { types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) - | (1 << JVM_CONSTANT_String) | (1 << JVM_CONSTANT_Class); + | (1 << JVM_CONSTANT_String) | (1 << JVM_CONSTANT_Class) + | (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType); + // Note: The class file parser already verified the legality of + // MethodHandle and MethodType constants. verify_cp_type(index, cp, types, CHECK_VERIFY(this)); } } else { @@ -1632,6 +1635,14 @@ current_frame->push_stack_2( VerificationType::long_type(), VerificationType::long2_type(), CHECK_VERIFY(this)); + } else if (tag.is_method_handle()) { + current_frame->push_stack( + VerificationType::reference_type( + vmSymbols::java_dyn_MethodHandle()), CHECK_VERIFY(this)); + } else if (tag.is_method_type()) { + current_frame->push_stack( + VerificationType::reference_type( + vmSymbols::java_dyn_MethodType()), CHECK_VERIFY(this)); } else { verify_error(bci, "Invalid index in ldc"); return; @@ -1920,9 +1931,12 @@ // Get referenced class type VerificationType ref_class_type; if (opcode == Bytecodes::_invokedynamic) { - if (!EnableInvokeDynamic) { + if (!EnableInvokeDynamic || + _klass->major_version() < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { class_format_error( - "invokedynamic instructions not enabled on this JVM", + (!EnableInvokeDynamic ? + "invokedynamic instructions not enabled in this JVM" : + "invokedynamic instructions not supported by this class file version"), _klass->external_name()); return; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/classfile/verifier.hpp --- a/hotspot/src/share/vm/classfile/verifier.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/classfile/verifier.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -25,7 +25,10 @@ // The verifier class class Verifier : AllStatic { public: - enum { STACKMAP_ATTRIBUTE_MAJOR_VERSION = 50 }; + enum { + STACKMAP_ATTRIBUTE_MAJOR_VERSION = 50, + INVOKEDYNAMIC_MAJOR_VERSION = 51 + }; typedef enum { ThrowException, NoException } Mode; /** diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -246,6 +246,8 @@ /* internal up-calls made only by the JVM, via class sun.dyn.MethodHandleNatives: */ \ template(findMethodHandleType_name, "findMethodHandleType") \ template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/dyn/MethodType;") \ + template(linkMethodHandleConstant_name, "linkMethodHandleConstant") \ + template(linkMethodHandleConstant_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/dyn/MethodHandle;") \ template(makeDynamicCallSite_name, "makeDynamicCallSite") \ template(makeDynamicCallSite_signature, "(Ljava/dyn/MethodHandle;Ljava/lang/String;Ljava/dyn/MethodType;Ljava/lang/Object;Lsun/dyn/MemberName;I)Ljava/dyn/CallSite;") \ NOT_LP64( do_alias(machine_word_signature, int_signature) ) \ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/code/codeBlob.cpp --- a/hotspot/src/share/vm/code/codeBlob.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/code/codeBlob.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -210,6 +210,7 @@ { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); blob = new (size) AdapterBlob(size, cb); + CodeCache::commit(blob); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); @@ -281,7 +282,6 @@ tty->print_cr("Decoding %s " INTPTR_FORMAT, stub_id, stub); Disassembler::decode(stub->instructions_begin(), stub->instructions_end()); } - VTune::register_stub(stub_id, stub->instructions_begin(), stub->instructions_end()); Forte::register_stub(stub_id, stub->instructions_begin(), stub->instructions_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { @@ -356,7 +356,6 @@ tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob); Disassembler::decode(blob->instructions_begin(), blob->instructions_end()); } - VTune::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { @@ -414,7 +413,6 @@ tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob); Disassembler::decode(blob->instructions_begin(), blob->instructions_end()); } - VTune::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { @@ -474,7 +472,6 @@ tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob); Disassembler::decode(blob->instructions_begin(), blob->instructions_end()); } - VTune::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { @@ -533,7 +530,6 @@ tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob); Disassembler::decode(blob->instructions_begin(), blob->instructions_end()); } - VTune::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -93,6 +93,8 @@ CodeHeap * CodeCache::_heap = new CodeHeap(); int CodeCache::_number_of_blobs = 0; +int CodeCache::_number_of_adapters = 0; +int CodeCache::_number_of_nmethods = 0; int CodeCache::_number_of_nmethods_with_dependencies = 0; bool CodeCache::_needs_cache_clean = false; nmethod* CodeCache::_scavenge_root_nmethods = NULL; @@ -176,8 +178,14 @@ verify_if_often(); print_trace("free", cb); - if (cb->is_nmethod() && ((nmethod *)cb)->has_dependencies()) { - _number_of_nmethods_with_dependencies--; + if (cb->is_nmethod()) { + _number_of_nmethods--; + if (((nmethod *)cb)->has_dependencies()) { + _number_of_nmethods_with_dependencies--; + } + } + if (cb->is_adapter_blob()) { + _number_of_adapters--; } _number_of_blobs--; @@ -191,9 +199,16 @@ void CodeCache::commit(CodeBlob* cb) { // this is called by nmethod::nmethod, which must already own CodeCache_lock assert_locked_or_safepoint(CodeCache_lock); - if (cb->is_nmethod() && ((nmethod *)cb)->has_dependencies()) { - _number_of_nmethods_with_dependencies++; + if (cb->is_nmethod()) { + _number_of_nmethods++; + if (((nmethod *)cb)->has_dependencies()) { + _number_of_nmethods_with_dependencies++; + } } + if (cb->is_adapter_blob()) { + _number_of_adapters++; + } + // flush the hardware I-cache ICache::invalidate_range(cb->instructions_begin(), cb->instructions_size()); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/code/codeCache.hpp --- a/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,8 @@ // 4422213 or 4436291 for details. static CodeHeap * _heap; static int _number_of_blobs; + static int _number_of_adapters; + static int _number_of_nmethods; static int _number_of_nmethods_with_dependencies; static bool _needs_cache_clean; static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link() @@ -105,6 +107,8 @@ static nmethod* first_nmethod(); static nmethod* next_nmethod (CodeBlob* cb); static int nof_blobs() { return _number_of_blobs; } + static int nof_adapters() { return _number_of_adapters; } + static int nof_nmethods() { return _number_of_nmethods; } // GC support static void gc_epilogue(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -397,11 +397,6 @@ //-------------end of code for ExceptionCache-------------- -void nmFlags::clear() { - assert(sizeof(nmFlags) == sizeof(int), "using more than one word for nmFlags"); - *(jint*)this = 0; -} - int nmethod::total_size() const { return code_size() + @@ -419,8 +414,32 @@ return NULL; } -// %%% This variable is no longer used? -int nmethod::_zombie_instruction_size = NativeJump::instruction_size; +// Fill in default values for various flag fields +void nmethod::init_defaults() { + _state = alive; + _marked_for_reclamation = 0; + _has_flushed_dependencies = 0; + _speculatively_disconnected = 0; + _has_unsafe_access = 0; + _has_method_handle_invokes = 0; + _marked_for_deoptimization = 0; + _lock_count = 0; + _stack_traversal_mark = 0; + _unload_reported = false; // jvmti state + + NOT_PRODUCT(_has_debug_info = false); + _oops_do_mark_link = NULL; + _jmethod_id = NULL; + _osr_link = NULL; + _scavenge_root_link = NULL; + _scavenge_root_state = 0; + _saved_nmethod_link = NULL; + _compiler = NULL; + +#ifdef HAVE_DTRACE_H + _trap_offset = 0; +#endif // def HAVE_DTRACE_H +} nmethod* nmethod::new_native_nmethod(methodHandle method, @@ -580,24 +599,16 @@ debug_only(No_Safepoint_Verifier nsv;) assert_locked_or_safepoint(CodeCache_lock); - NOT_PRODUCT(_has_debug_info = false); - _oops_do_mark_link = NULL; + init_defaults(); _method = method; _entry_bci = InvocationEntryBci; - _osr_link = NULL; - _scavenge_root_link = NULL; - _scavenge_root_state = 0; - _saved_nmethod_link = NULL; - _compiler = NULL; // We have no exception handler or deopt handler make the // values something that will never match a pc like the nmethod vtable entry _exception_offset = 0; _deoptimize_offset = 0; _deoptimize_mh_offset = 0; _orig_pc_offset = 0; -#ifdef HAVE_DTRACE_H - _trap_offset = 0; -#endif // def HAVE_DTRACE_H + _stub_offset = data_offset(); _consts_offset = data_offset(); _oops_offset = data_offset(); @@ -615,17 +626,9 @@ _exception_cache = NULL; _pc_desc_cache.reset_to(NULL); - flags.clear(); - flags.state = alive; - _markedForDeoptimization = 0; - - _lock_count = 0; - _stack_traversal_mark = 0; - code_buffer->copy_oops_to(this); debug_only(verify_scavenge_root_oops()); CodeCache::commit(this); - VTune::create_nmethod(this); } if (PrintNativeNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { @@ -673,14 +676,9 @@ debug_only(No_Safepoint_Verifier nsv;) assert_locked_or_safepoint(CodeCache_lock); - NOT_PRODUCT(_has_debug_info = false); - _oops_do_mark_link = NULL; + init_defaults(); _method = method; _entry_bci = InvocationEntryBci; - _osr_link = NULL; - _scavenge_root_link = NULL; - _scavenge_root_state = 0; - _compiler = NULL; // We have no exception handler or deopt handler make the // values something that will never match a pc like the nmethod vtable entry _exception_offset = 0; @@ -706,17 +704,9 @@ _exception_cache = NULL; _pc_desc_cache.reset_to(NULL); - flags.clear(); - flags.state = alive; - _markedForDeoptimization = 0; - - _lock_count = 0; - _stack_traversal_mark = 0; - code_buffer->copy_oops_to(this); debug_only(verify_scavenge_root_oops()); CodeCache::commit(this); - VTune::create_nmethod(this); } if (PrintNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { @@ -781,20 +771,13 @@ debug_only(No_Safepoint_Verifier nsv;) assert_locked_or_safepoint(CodeCache_lock); - NOT_PRODUCT(_has_debug_info = false); - _oops_do_mark_link = NULL; + init_defaults(); _method = method; + _entry_bci = entry_bci; _compile_id = compile_id; _comp_level = comp_level; - _entry_bci = entry_bci; - _osr_link = NULL; - _scavenge_root_link = NULL; - _scavenge_root_state = 0; _compiler = compiler; _orig_pc_offset = orig_pc_offset; -#ifdef HAVE_DTRACE_H - _trap_offset = 0; -#endif // def HAVE_DTRACE_H _stub_offset = instructions_offset() + code_buffer->total_offset_of(code_buffer->stubs()->start()); // Exception handler and deopt handler are in the stub section @@ -821,15 +804,6 @@ _exception_cache = NULL; _pc_desc_cache.reset_to(scopes_pcs_begin()); - flags.clear(); - flags.state = alive; - _markedForDeoptimization = 0; - - _unload_reported = false; // jvmti state - - _lock_count = 0; - _stack_traversal_mark = 0; - // Copy contents of ScopeDescRecorder to nmethod code_buffer->copy_oops_to(this); debug_info->copy_to(this); @@ -841,8 +815,6 @@ CodeCache::commit(this); - VTune::create_nmethod(this); - // Copy contents of ExceptionHandlerTable to nmethod handler_table->copy_to(this); nul_chk_table->copy_to(this); @@ -988,11 +960,6 @@ } -void nmethod::set_version(int v) { - flags.version = v; -} - - // Promote one word from an assembly-time handle to a live embedded oop. inline void nmethod::initialize_immediate_oop(oop* dest, jobject handle) { if (handle == NULL || @@ -1139,6 +1106,8 @@ // This is a private interface with the sweeper. void nmethod::mark_as_seen_on_stack() { assert(is_not_entrant(), "must be a non-entrant method"); + // Set the traversal mark to ensure that the sweeper does 2 + // cleaning passes before moving to zombie. set_stack_traversal_mark(NMethodSweeper::traversal_count()); } @@ -1207,7 +1176,7 @@ // for later on. CodeCache::set_needs_cache_clean(true); } - flags.state = unloaded; + _state = unloaded; // Log the unloading. log_state_change(); @@ -1233,21 +1202,21 @@ if (LogCompilation) { if (xtty != NULL) { ttyLocker ttyl; // keep the following output all in one block - if (flags.state == unloaded) { + if (_state == unloaded) { xtty->begin_elem("make_unloaded thread='" UINTX_FORMAT "'", os::current_thread_id()); } else { xtty->begin_elem("make_not_entrant thread='" UINTX_FORMAT "'%s", os::current_thread_id(), - (flags.state == zombie ? " zombie='1'" : "")); + (_state == zombie ? " zombie='1'" : "")); } log_identity(xtty); xtty->stamp(); xtty->end_elem(); } } - if (PrintCompilation && flags.state != unloaded) { - print_on(tty, flags.state == zombie ? "made zombie " : "made not entrant "); + if (PrintCompilation && _state != unloaded) { + print_on(tty, _state == zombie ? "made zombie " : "made not entrant "); tty->cr(); } } @@ -1258,8 +1227,9 @@ bool was_alive = false; - // Make sure the nmethod is not flushed in case of a safepoint in code below. + // Make sure neither the nmethod nor the method is flushed in case of a safepoint in code below. nmethodLocker nml(this); + methodHandle the_method(method()); { // If the method is already zombie there is nothing to do @@ -1279,7 +1249,7 @@ // Enter critical section. Does not block for safepoint. MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); - if (flags.state == state) { + if (_state == state) { // another thread already performed this transition so nothing // to do, but return false to indicate this. return false; @@ -1290,17 +1260,37 @@ if (!is_osr_method() && !is_not_entrant()) { NativeJump::patch_verified_entry(entry_point(), verified_entry_point(), SharedRuntime::get_handle_wrong_method_stub()); - assert (NativeJump::instruction_size == nmethod::_zombie_instruction_size, ""); } - was_alive = is_in_use(); // Read state under lock + if (is_in_use()) { + // It's a true state change, so mark the method as decompiled. + // Do it only for transition from alive. + inc_decompile_count(); + } // Change state - flags.state = state; + _state = state; // Log the transition once log_state_change(); + // Remove nmethod from method. + // We need to check if both the _code and _from_compiled_code_entry_point + // refer to this nmethod because there is a race in setting these two fields + // in methodOop as seen in bugid 4947125. + // If the vep() points to the zombie nmethod, the memory for the nmethod + // could be flushed and the compiler and vtable stubs could still call + // through it. + if (method() != NULL && (method()->code() == this || + method()->from_compiled_entry() == verified_entry_point())) { + HandleMark hm; + method()->clear_code(); + } + + if (state == not_entrant) { + mark_as_seen_on_stack(); + } + } // leave critical region under Patching_lock // When the nmethod becomes zombie it is no longer alive so the @@ -1308,18 +1298,17 @@ // state will be flushed later when the transition to zombie // happens or they get unloaded. if (state == zombie) { + // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event + // and it hasn't already been reported for this nmethod then report it now. + // (the event may have been reported earilier if the GC marked it for unloading). + post_compiled_method_unload(); + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); flush_dependencies(NULL); } else { assert(state == not_entrant, "other cases may need to be handled differently"); } - if (state == not_entrant) { - Events::log("Make nmethod not entrant " INTPTR_FORMAT, this); - } else { - Events::log("Make nmethod zombie " INTPTR_FORMAT, this); - } - if (TraceCreateZombies) { tty->print_cr("nmethod <" INTPTR_FORMAT "> code made %s", this, (state == not_entrant) ? "not entrant" : "zombie"); } @@ -1327,47 +1316,6 @@ // Make sweeper aware that there is a zombie method that needs to be removed NMethodSweeper::notify(this); - // not_entrant only stuff - if (state == not_entrant) { - mark_as_seen_on_stack(); - } - - if (was_alive) { - // It's a true state change, so mark the method as decompiled. - // Do it only for transition from alive. - inc_decompile_count(); - } - - // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event - // and it hasn't already been reported for this nmethod then report it now. - // (the event may have been reported earilier if the GC marked it for unloading). - if (state == zombie) { - post_compiled_method_unload(); - } - - - // Zombie only stuff - if (state == zombie) { - VTune::delete_nmethod(this); - } - - // Check whether method got unloaded at a safepoint before this, - // if so we can skip the flushing steps below - if (method() == NULL) return true; - - // Remove nmethod from method. - // We need to check if both the _code and _from_compiled_code_entry_point - // refer to this nmethod because there is a race in setting these two fields - // in methodOop as seen in bugid 4947125. - // If the vep() points to the zombie nmethod, the memory for the nmethod - // could be flushed and the compiler and vtable stubs could still call - // through it. - if (method()->code() == this || - method()->from_compiled_entry() == verified_entry_point()) { - HandleMark hm; - method()->clear_code(); - } - return true; } @@ -1488,11 +1436,25 @@ moop->signature()->utf8_length(), code_begin(), code_size()); + if (JvmtiExport::should_post_compiled_method_load() || + JvmtiExport::should_post_compiled_method_unload()) { + get_and_cache_jmethod_id(); + } + if (JvmtiExport::should_post_compiled_method_load()) { JvmtiExport::post_compiled_method_load(this); } } +jmethodID nmethod::get_and_cache_jmethod_id() { + if (_jmethod_id == NULL) { + // Cache the jmethod_id since it can no longer be looked up once the + // method itself has been marked for unloading. + _jmethod_id = method()->jmethod_id(); + } + return _jmethod_id; +} + void nmethod::post_compiled_method_unload() { if (unload_reported()) { // During unloading we transition to unloaded and then to zombie @@ -1504,12 +1466,17 @@ DTRACE_METHOD_UNLOAD_PROBE(method()); // If a JVMTI agent has enabled the CompiledMethodUnload event then - // post the event. Sometime later this nmethod will be made a zombie by - // the sweeper but the methodOop will not be valid at that point. - if (JvmtiExport::should_post_compiled_method_unload()) { + // post the event. Sometime later this nmethod will be made a zombie + // by the sweeper but the methodOop will not be valid at that point. + // If the _jmethod_id is null then no load event was ever requested + // so don't bother posting the unload. The main reason for this is + // that the jmethodID is a weak reference to the methodOop so if + // it's being unloaded there's no way to look it up since the weak + // ref will have been cleared. + if (_jmethod_id != NULL && JvmtiExport::should_post_compiled_method_unload()) { assert(!unload_reported(), "already unloaded"); HandleMark hm; - JvmtiExport::post_compiled_method_unload(method()->jmethod_id(), code_begin()); + JvmtiExport::post_compiled_method_unload(_jmethod_id, code_begin()); } // The JVMTI CompiledMethodUnload event can be enabled or disabled at @@ -2087,7 +2054,6 @@ void nmethod_init() { // make sure you didn't forget to adjust the filler fields - assert(sizeof(nmFlags) <= 4, "nmFlags occupies more than a word"); assert(sizeof(nmethod) % oopSize == 0, "nmethod size must be multiple of a word"); } @@ -2323,7 +2289,6 @@ tty->print("((nmethod*) "INTPTR_FORMAT ") ", this); tty->print(" for method " INTPTR_FORMAT , (address)method()); tty->print(" { "); - if (version()) tty->print("v%d ", version()); if (is_in_use()) tty->print("in_use "); if (is_not_entrant()) tty->print("not_entrant "); if (is_zombie()) tty->print("zombie "); @@ -2659,13 +2624,10 @@ case Bytecodes::_getstatic: case Bytecodes::_putstatic: { - methodHandle sdm = sd->method(); - Bytecode_field* field = Bytecode_field_at(sdm(), sdm->bcp_from(sd->bci())); - constantPoolOop sdmc = sdm->constants(); - symbolOop name = sdmc->name_ref_at(field->index()); + Bytecode_field* field = Bytecode_field_at(sd->method(), sd->bci()); st->print(" "); - if (name != NULL) - name->print_symbol_on(st); + if (field->name() != NULL) + field->name()->print_symbol_on(st); else st->print(""); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/code/nmethod.hpp --- a/hotspot/src/share/vm/code/nmethod.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/code/nmethod.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -78,29 +78,8 @@ // nmethods (native methods) are the compiled code versions of Java methods. - -struct nmFlags { - friend class VMStructs; - unsigned int version:8; // version number (0 = first version) - unsigned int age:4; // age (in # of sweep steps) - - unsigned int state:2; // {alive, zombie, unloaded) - - unsigned int isUncommonRecompiled:1; // recompiled because of uncommon trap? - unsigned int isToBeRecompiled:1; // to be recompiled as soon as it matures - unsigned int hasFlushedDependencies:1; // Used for maintenance of dependencies - unsigned int markedForReclamation:1; // Used by NMethodSweeper - - unsigned int has_unsafe_access:1; // May fault due to unsafe access. - unsigned int has_method_handle_invokes:1; // Has this method MethodHandle invokes? - - unsigned int speculatively_disconnected:1; // Marked for potential unload - - void clear(); -}; - - -// A nmethod contains: +// +// An nmethod contains: // - header (the nmethod structure) // [Relocation] // - relocation information @@ -131,10 +110,9 @@ friend class CodeCache; // non-perm oops private: // Shared fields for all nmethod's - static int _zombie_instruction_size; - methodOop _method; int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method + jmethodID _jmethod_id; // Cache of method()->jmethod_id() // To support simple linked-list chaining of nmethods: nmethod* _osr_link; // from instanceKlass::osr_nmethods_head @@ -146,6 +124,11 @@ AbstractCompiler* _compiler; // The compiler which compiled this nmethod + // offsets for entry points + address _entry_point; // entry point with class check + address _verified_entry_point; // entry point without class check + address _osr_entry_point; // entry point for on stack replacement + // Offsets for different nmethod parts int _exception_offset; // All deoptee's will resume execution at this location described by @@ -174,23 +157,31 @@ // pc during a deopt. int _orig_pc_offset; - int _compile_id; // which compilation made this nmethod - int _comp_level; // compilation level + int _compile_id; // which compilation made this nmethod + int _comp_level; // compilation level + + // protected by CodeCache_lock + bool _has_flushed_dependencies; // Used for maintenance of dependencies (CodeCache_lock) + bool _speculatively_disconnected; // Marked for potential unload + + bool _marked_for_reclamation; // Used by NMethodSweeper (set only by sweeper) + bool _marked_for_deoptimization; // Used for stack deoptimization - // offsets for entry points - address _entry_point; // entry point with class check - address _verified_entry_point; // entry point without class check - address _osr_entry_point; // entry point for on stack replacement + // used by jvmti to track if an unload event has been posted for this nmethod. + bool _unload_reported; - nmFlags flags; // various flags to keep track of nmethod state - bool _markedForDeoptimization; // Used for stack deoptimization + // set during construction + unsigned int _has_unsafe_access:1; // May fault due to unsafe access. + unsigned int _has_method_handle_invokes:1; // Has this method MethodHandle invokes? + + // Protected by Patching_lock + unsigned char _state; // {alive, not_entrant, zombie, unloaded) + enum { alive = 0, not_entrant = 1, // uncommon trap has happened but activations may still exist zombie = 2, unloaded = 3 }; - // used by jvmti to track if an unload event has been posted for this nmethod. - bool _unload_reported; jbyte _scavenge_root_state; @@ -269,15 +260,15 @@ bool make_not_entrant_or_zombie(unsigned int state); void inc_decompile_count(); - // used to check that writes to nmFlags are done consistently. - static void check_safepoint() PRODUCT_RETURN; - // Used to manipulate the exception cache void add_exception_cache_entry(ExceptionCache* new_entry); ExceptionCache* exception_cache_entry_for_exception(Handle exception); // Inform external interfaces that a compiled method has been unloaded - inline void post_compiled_method_unload(); + void post_compiled_method_unload(); + + // Initailize fields to their default values + void init_defaults(); public: // create nmethod with entry_bci @@ -392,11 +383,11 @@ address verified_entry_point() const { return _verified_entry_point; } // if klass is correct // flag accessing and manipulation - bool is_in_use() const { return flags.state == alive; } - bool is_alive() const { return flags.state == alive || flags.state == not_entrant; } - bool is_not_entrant() const { return flags.state == not_entrant; } - bool is_zombie() const { return flags.state == zombie; } - bool is_unloaded() const { return flags.state == unloaded; } + bool is_in_use() const { return _state == alive; } + bool is_alive() const { return _state == alive || _state == not_entrant; } + bool is_not_entrant() const { return _state == not_entrant; } + bool is_zombie() const { return _state == zombie; } + bool is_unloaded() const { return _state == unloaded; } // Make the nmethod non entrant. The nmethod will continue to be // alive. It is used when an uncommon trap happens. Returns true @@ -409,37 +400,33 @@ bool unload_reported() { return _unload_reported; } void set_unload_reported() { _unload_reported = true; } - bool is_marked_for_deoptimization() const { return _markedForDeoptimization; } - void mark_for_deoptimization() { _markedForDeoptimization = true; } + bool is_marked_for_deoptimization() const { return _marked_for_deoptimization; } + void mark_for_deoptimization() { _marked_for_deoptimization = true; } void make_unloaded(BoolObjectClosure* is_alive, oop cause); bool has_dependencies() { return dependencies_size() != 0; } void flush_dependencies(BoolObjectClosure* is_alive); - bool has_flushed_dependencies() { return flags.hasFlushedDependencies; } - void set_has_flushed_dependencies() { + bool has_flushed_dependencies() { return _has_flushed_dependencies; } + void set_has_flushed_dependencies() { assert(!has_flushed_dependencies(), "should only happen once"); - flags.hasFlushedDependencies = 1; + _has_flushed_dependencies = 1; } - bool is_marked_for_reclamation() const { return flags.markedForReclamation; } - void mark_for_reclamation() { flags.markedForReclamation = 1; } - void unmark_for_reclamation() { flags.markedForReclamation = 0; } + bool is_marked_for_reclamation() const { return _marked_for_reclamation; } + void mark_for_reclamation() { _marked_for_reclamation = 1; } + + bool has_unsafe_access() const { return _has_unsafe_access; } + void set_has_unsafe_access(bool z) { _has_unsafe_access = z; } - bool has_unsafe_access() const { return flags.has_unsafe_access; } - void set_has_unsafe_access(bool z) { flags.has_unsafe_access = z; } + bool has_method_handle_invokes() const { return _has_method_handle_invokes; } + void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - bool has_method_handle_invokes() const { return flags.has_method_handle_invokes; } - void set_has_method_handle_invokes(bool z) { flags.has_method_handle_invokes = z; } - - bool is_speculatively_disconnected() const { return flags.speculatively_disconnected; } - void set_speculatively_disconnected(bool z) { flags.speculatively_disconnected = z; } + bool is_speculatively_disconnected() const { return _speculatively_disconnected; } + void set_speculatively_disconnected(bool z) { _speculatively_disconnected = z; } int comp_level() const { return _comp_level; } - int version() const { return flags.version; } - void set_version(int v); - // Support for oops in scopes and relocs: // Note: index 0 is reserved for null. oop oop_at(int index) const { return index == 0 ? (oop) NULL: *oop_addr_at(index); } @@ -599,6 +586,7 @@ // jvmti support: void post_compiled_method_load_event(); + jmethodID get_and_cache_jmethod_id(); // verify operations void verify(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/code/vtableStubs.cpp --- a/hotspot/src/share/vm/code/vtableStubs.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/code/vtableStubs.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,6 @@ } _chunk = blob->instructions_begin(); _chunk_end = _chunk + bytes; - VTune::register_stub("vtable stub", _chunk, _chunk_end); Forte::register_stub("vtable stub", _chunk, _chunk_end); // Notify JVMTI about this stub. The event will be recorded by the enclosing // JvmtiDynamicCodeEventCollector and posted when this thread has released diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -3972,6 +3972,10 @@ void work(int i) { if (i >= _n_workers) return; // no work needed this round + + double start_time_ms = os::elapsedTime() * 1000.0; + _g1h->g1_policy()->record_gc_worker_start_time(i, start_time_ms); + ResourceMark rm; HandleMark hm; @@ -4019,7 +4023,7 @@ double elapsed_ms = (os::elapsedTime()-start)*1000.0; double term_ms = pss.term_time()*1000.0; _g1h->g1_policy()->record_obj_copy_time(i, elapsed_ms-term_ms); - _g1h->g1_policy()->record_termination_time(i, term_ms); + _g1h->g1_policy()->record_termination(i, term_ms, pss.term_attempts()); } _g1h->g1_policy()->record_thread_age_table(pss.age_table()); _g1h->update_surviving_young_words(pss.surviving_young_words()+1); @@ -4043,7 +4047,8 @@ double term = pss.term_time(); gclog_or_tty->print(" Elapsed: %7.2f ms.\n" " Strong roots: %7.2f ms (%6.2f%%)\n" - " Termination: %7.2f ms (%6.2f%%) (in %d entries)\n", + " Termination: %7.2f ms (%6.2f%%) " + "(in "SIZE_FORMAT" entries)\n", elapsed * 1000.0, strong_roots * 1000.0, (strong_roots*100.0/elapsed), term * 1000.0, (term*100.0/elapsed), @@ -4059,6 +4064,8 @@ assert(pss.refs_to_scan() == 0, "Task queue should be empty"); assert(pss.overflowed_refs_to_scan() == 0, "Overflow queue should be empty"); + double end_time_ms = os::elapsedTime() * 1000.0; + _g1h->g1_policy()->record_gc_worker_end_time(i, end_time_ms); } }; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1549,7 +1549,7 @@ int _hash_seed; int _queue_num; - int _term_attempts; + size_t _term_attempts; #if G1_DETAILED_STATS int _pushes, _pops, _steals, _steal_attempts; int _overflow_pushes; @@ -1727,8 +1727,8 @@ int* hash_seed() { return &_hash_seed; } int queue_num() { return _queue_num; } - int term_attempts() { return _term_attempts; } - void note_term_attempt() { _term_attempts++; } + size_t term_attempts() { return _term_attempts; } + void note_term_attempt() { _term_attempts++; } #if G1_DETAILED_STATS int pushes() { return _pushes; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -231,20 +231,21 @@ _recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime()); _prev_collection_pause_end_ms = os::elapsedTime() * 1000.0; + _par_last_gc_worker_start_times_ms = new double[_parallel_gc_threads]; _par_last_ext_root_scan_times_ms = new double[_parallel_gc_threads]; _par_last_mark_stack_scan_times_ms = new double[_parallel_gc_threads]; - _par_last_update_rs_start_times_ms = new double[_parallel_gc_threads]; _par_last_update_rs_times_ms = new double[_parallel_gc_threads]; _par_last_update_rs_processed_buffers = new double[_parallel_gc_threads]; - _par_last_scan_rs_start_times_ms = new double[_parallel_gc_threads]; _par_last_scan_rs_times_ms = new double[_parallel_gc_threads]; _par_last_scan_new_refs_times_ms = new double[_parallel_gc_threads]; _par_last_obj_copy_times_ms = new double[_parallel_gc_threads]; _par_last_termination_times_ms = new double[_parallel_gc_threads]; + _par_last_termination_attempts = new double[_parallel_gc_threads]; + _par_last_gc_worker_end_times_ms = new double[_parallel_gc_threads]; // start conservatively _expensive_region_limit_ms = 0.5 * (double) MaxGCPauseMillis; @@ -274,10 +275,64 @@ // - double time_slice = (double) GCPauseIntervalMillis / 1000.0; + // Below, we might need to calculate the pause time target based on + // the pause interval. When we do so we are going to give G1 maximum + // flexibility and allow it to do pauses when it needs to. So, we'll + // arrange that the pause interval to be pause time target + 1 to + // ensure that a) the pause time target is maximized with respect to + // the pause interval and b) we maintain the invariant that pause + // time target < pause interval. If the user does not want this + // maximum flexibility, they will have to set the pause interval + // explicitly. + + // First make sure that, if either parameter is set, its value is + // reasonable. + if (!FLAG_IS_DEFAULT(MaxGCPauseMillis)) { + if (MaxGCPauseMillis < 1) { + vm_exit_during_initialization("MaxGCPauseMillis should be " + "greater than 0"); + } + } + if (!FLAG_IS_DEFAULT(GCPauseIntervalMillis)) { + if (GCPauseIntervalMillis < 1) { + vm_exit_during_initialization("GCPauseIntervalMillis should be " + "greater than 0"); + } + } + + // Then, if the pause time target parameter was not set, set it to + // the default value. + if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) { + if (FLAG_IS_DEFAULT(GCPauseIntervalMillis)) { + // The default pause time target in G1 is 200ms + FLAG_SET_DEFAULT(MaxGCPauseMillis, 200); + } else { + // We do not allow the pause interval to be set without the + // pause time target + vm_exit_during_initialization("GCPauseIntervalMillis cannot be set " + "without setting MaxGCPauseMillis"); + } + } + + // Then, if the interval parameter was not set, set it according to + // the pause time target (this will also deal with the case when the + // pause time target is the default value). + if (FLAG_IS_DEFAULT(GCPauseIntervalMillis)) { + FLAG_SET_DEFAULT(GCPauseIntervalMillis, MaxGCPauseMillis + 1); + } + + // Finally, make sure that the two parameters are consistent. + if (MaxGCPauseMillis >= GCPauseIntervalMillis) { + char buffer[256]; + jio_snprintf(buffer, 256, + "MaxGCPauseMillis (%u) should be less than " + "GCPauseIntervalMillis (%u)", + MaxGCPauseMillis, GCPauseIntervalMillis); + vm_exit_during_initialization(buffer); + } + double max_gc_time = (double) MaxGCPauseMillis / 1000.0; - guarantee(max_gc_time < time_slice, - "Max GC time should not be greater than the time slice"); + double time_slice = (double) GCPauseIntervalMillis / 1000.0; _mmu_tracker = new G1MMUTrackerQueue(time_slice, max_gc_time); _sigma = (double) G1ConfidencePercent / 100.0; @@ -782,16 +837,17 @@ // if they are not set properly for (int i = 0; i < _parallel_gc_threads; ++i) { - _par_last_ext_root_scan_times_ms[i] = -666.0; - _par_last_mark_stack_scan_times_ms[i] = -666.0; - _par_last_update_rs_start_times_ms[i] = -666.0; - _par_last_update_rs_times_ms[i] = -666.0; - _par_last_update_rs_processed_buffers[i] = -666.0; - _par_last_scan_rs_start_times_ms[i] = -666.0; - _par_last_scan_rs_times_ms[i] = -666.0; - _par_last_scan_new_refs_times_ms[i] = -666.0; - _par_last_obj_copy_times_ms[i] = -666.0; - _par_last_termination_times_ms[i] = -666.0; + _par_last_gc_worker_start_times_ms[i] = -1234.0; + _par_last_ext_root_scan_times_ms[i] = -1234.0; + _par_last_mark_stack_scan_times_ms[i] = -1234.0; + _par_last_update_rs_times_ms[i] = -1234.0; + _par_last_update_rs_processed_buffers[i] = -1234.0; + _par_last_scan_rs_times_ms[i] = -1234.0; + _par_last_scan_new_refs_times_ms[i] = -1234.0; + _par_last_obj_copy_times_ms[i] = -1234.0; + _par_last_termination_times_ms[i] = -1234.0; + _par_last_termination_attempts[i] = -1234.0; + _par_last_gc_worker_end_times_ms[i] = -1234.0; } #endif @@ -942,9 +998,9 @@ return sum; } -void G1CollectorPolicy::print_par_stats (int level, - const char* str, - double* data, +void G1CollectorPolicy::print_par_stats(int level, + const char* str, + double* data, bool summary) { double min = data[0], max = data[0]; double total = 0.0; @@ -973,10 +1029,10 @@ gclog_or_tty->print_cr("]"); } -void G1CollectorPolicy::print_par_buffers (int level, - const char* str, - double* data, - bool summary) { +void G1CollectorPolicy::print_par_sizes(int level, + const char* str, + double* data, + bool summary) { double min = data[0], max = data[0]; double total = 0.0; int j; @@ -1321,15 +1377,22 @@ } if (parallel) { print_stats(1, "Parallel Time", _cur_collection_par_time_ms); - print_par_stats(2, "Update RS (Start)", _par_last_update_rs_start_times_ms, false); + print_par_stats(2, "GC Worker Start Time", + _par_last_gc_worker_start_times_ms, false); print_par_stats(2, "Update RS", _par_last_update_rs_times_ms); - print_par_buffers(3, "Processed Buffers", - _par_last_update_rs_processed_buffers, true); - print_par_stats(2, "Ext Root Scanning", _par_last_ext_root_scan_times_ms); - print_par_stats(2, "Mark Stack Scanning", _par_last_mark_stack_scan_times_ms); + print_par_sizes(3, "Processed Buffers", + _par_last_update_rs_processed_buffers, true); + print_par_stats(2, "Ext Root Scanning", + _par_last_ext_root_scan_times_ms); + print_par_stats(2, "Mark Stack Scanning", + _par_last_mark_stack_scan_times_ms); print_par_stats(2, "Scan RS", _par_last_scan_rs_times_ms); print_par_stats(2, "Object Copy", _par_last_obj_copy_times_ms); print_par_stats(2, "Termination", _par_last_termination_times_ms); + print_par_sizes(3, "Termination Attempts", + _par_last_termination_attempts, true); + print_par_stats(2, "GC Worker End Time", + _par_last_gc_worker_end_times_ms, false); print_stats(2, "Other", parallel_other_time); print_stats(1, "Clear CT", _cur_clear_ct_time_ms); } else { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -171,16 +171,17 @@ double* _cur_aux_times_ms; bool* _cur_aux_times_set; + double* _par_last_gc_worker_start_times_ms; double* _par_last_ext_root_scan_times_ms; double* _par_last_mark_stack_scan_times_ms; - double* _par_last_update_rs_start_times_ms; double* _par_last_update_rs_times_ms; double* _par_last_update_rs_processed_buffers; - double* _par_last_scan_rs_start_times_ms; double* _par_last_scan_rs_times_ms; double* _par_last_scan_new_refs_times_ms; double* _par_last_obj_copy_times_ms; double* _par_last_termination_times_ms; + double* _par_last_termination_attempts; + double* _par_last_gc_worker_end_times_ms; // indicates that we are in young GC mode bool _in_young_gc_mode; @@ -559,13 +560,14 @@ } protected: - void print_stats (int level, const char* str, double value); - void print_stats (int level, const char* str, int value); - void print_par_stats (int level, const char* str, double* data) { + void print_stats(int level, const char* str, double value); + void print_stats(int level, const char* str, int value); + + void print_par_stats(int level, const char* str, double* data) { print_par_stats(level, str, data, true); } - void print_par_stats (int level, const char* str, double* data, bool summary); - void print_par_buffers (int level, const char* str, double* data, bool summary); + void print_par_stats(int level, const char* str, double* data, bool summary); + void print_par_sizes(int level, const char* str, double* data, bool summary); void check_other_times(int level, NumberSeq* other_times_ms, @@ -891,6 +893,10 @@ virtual void record_full_collection_start(); virtual void record_full_collection_end(); + void record_gc_worker_start_time(int worker_i, double ms) { + _par_last_gc_worker_start_times_ms[worker_i] = ms; + } + void record_ext_root_scan_time(int worker_i, double ms) { _par_last_ext_root_scan_times_ms[worker_i] = ms; } @@ -912,10 +918,6 @@ _all_mod_union_times_ms->add(ms); } - void record_update_rs_start_time(int thread, double ms) { - _par_last_update_rs_start_times_ms[thread] = ms; - } - void record_update_rs_time(int thread, double ms) { _par_last_update_rs_times_ms[thread] = ms; } @@ -925,10 +927,6 @@ _par_last_update_rs_processed_buffers[thread] = processed_buffers; } - void record_scan_rs_start_time(int thread, double ms) { - _par_last_scan_rs_start_times_ms[thread] = ms; - } - void record_scan_rs_time(int thread, double ms) { _par_last_scan_rs_times_ms[thread] = ms; } @@ -953,16 +951,13 @@ _par_last_obj_copy_times_ms[thread] += ms; } - void record_obj_copy_time(double ms) { - record_obj_copy_time(0, ms); + void record_termination(int thread, double ms, size_t attempts) { + _par_last_termination_times_ms[thread] = ms; + _par_last_termination_attempts[thread] = (double) attempts; } - void record_termination_time(int thread, double ms) { - _par_last_termination_times_ms[thread] = ms; - } - - void record_termination_time(double ms) { - record_termination_time(0, ms); + void record_gc_worker_end_time(int worker_i, double ms) { + _par_last_gc_worker_end_times_ms[worker_i] = ms; } void record_pause_time_ms(double ms) { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -303,7 +303,6 @@ assert( _cards_scanned != NULL, "invariant" ); _cards_scanned[worker_i] = scanRScl.cards_done(); - _g1p->record_scan_rs_start_time(worker_i, rs_time_start * 1000.0); _g1p->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0); } @@ -311,8 +310,6 @@ ConcurrentG1Refine* cg1r = _g1->concurrent_g1_refine(); double start = os::elapsedTime(); - _g1p->record_update_rs_start_time(worker_i, start * 1000.0); - // Apply the appropriate closure to all remaining log entries. _g1->iterate_dirty_card_closure(false, worker_i); // Now there should be no dirty cards. @@ -471,7 +468,6 @@ updateRS(worker_i); scanNewRefsRS(oc, worker_i); } else { - _g1p->record_update_rs_start_time(worker_i, os::elapsedTime() * 1000.0); _g1p->record_update_rs_processed_buffers(worker_i, 0.0); _g1p->record_update_rs_time(worker_i, 0.0); _g1p->record_scan_new_refs_time(worker_i, 0.0); @@ -479,7 +475,6 @@ if (G1UseParallelRSetScanning || (worker_i == 0)) { scanRS(oc, worker_i); } else { - _g1p->record_scan_rs_start_time(worker_i, os::elapsedTime() * 1000.0); _g1p->record_scan_rs_time(worker_i, 0.0); } } else { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Wed Jul 05 17:18:12 2017 +0200 @@ -270,7 +270,7 @@ psParallelCompact.cpp pcTasks.hpp psParallelCompact.cpp psMarkSweep.hpp psParallelCompact.cpp psMarkSweepDecorator.hpp -psParallelCompact.cpp psCompactionManager.hpp +psParallelCompact.cpp psCompactionManager.inline.hpp psParallelCompact.cpp psPromotionManager.inline.hpp psParallelCompact.cpp psOldGen.hpp psParallelCompact.cpp psParallelCompact.hpp diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -566,14 +566,14 @@ #endif // Commit new or uncommit old pages, if necessary. - resize_commit_uncommit(changed_region, new_region); + if (resize_commit_uncommit(changed_region, new_region)) { + // Set the new start of the committed region + resize_update_committed_table(changed_region, new_region); + } // Update card table entries resize_update_card_table_entries(changed_region, new_region); - // Set the new start of the committed region - resize_update_committed_table(changed_region, new_region); - // Update the covered region resize_update_covered_table(changed_region, new_region); @@ -604,8 +604,9 @@ debug_only(verify_guard();) } -void CardTableExtension::resize_commit_uncommit(int changed_region, +bool CardTableExtension::resize_commit_uncommit(int changed_region, MemRegion new_region) { + bool result = false; // Commit new or uncommit old pages, if necessary. MemRegion cur_committed = _committed[changed_region]; assert(_covered[changed_region].end() == new_region.end(), @@ -675,20 +676,31 @@ "card table expansion"); } } + result = true; } else if (new_start_aligned > cur_committed.start()) { // Shrink the committed region +#if 0 // uncommitting space is currently unsafe because of the interactions + // of growing and shrinking regions. One region A can uncommit space + // that it owns but which is being used by another region B (maybe). + // Region B has not committed the space because it was already + // committed by region A. MemRegion uncommit_region = committed_unique_to_self(changed_region, MemRegion(cur_committed.start(), new_start_aligned)); if (!uncommit_region.is_empty()) { if (!os::uncommit_memory((char*)uncommit_region.start(), uncommit_region.byte_size())) { - vm_exit_out_of_memory(uncommit_region.byte_size(), - "card table contraction"); + // If the uncommit fails, ignore it. Let the + // committed table resizing go even though the committed + // table will over state the committed space. } } +#else + assert(!result, "Should be false with current workaround"); +#endif } assert(_committed[changed_region].end() == cur_committed.end(), "end should not change"); + return result; } void CardTableExtension::resize_update_committed_table(int changed_region, diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,9 @@ class CardTableExtension : public CardTableModRefBS { private: // Support methods for resizing the card table. - void resize_commit_uncommit(int changed_region, MemRegion new_region); + // resize_commit_uncommit() returns true if the pages were committed or + // uncommitted + bool resize_commit_uncommit(int changed_region, MemRegion new_region); void resize_update_card_table_entries(int changed_region, MemRegion new_region); void resize_update_committed_table(int changed_region, MemRegion new_region); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ ParCompactionManager::_objarray_queues = NULL; ObjectStartArray* ParCompactionManager::_start_array = NULL; ParMarkBitMap* ParCompactionManager::_mark_bitmap = NULL; -RegionTaskQueueSet* ParCompactionManager::_region_array = NULL; +RegionTaskQueueSet* ParCompactionManager::_region_array = NULL; ParCompactionManager::ParCompactionManager() : _action(CopyAndUpdate) { @@ -43,25 +43,9 @@ _old_gen = heap->old_gen(); _start_array = old_gen()->start_array(); - marking_stack()->initialize(); - - // We want the overflow stack to be permanent - _overflow_stack = new (ResourceObj::C_HEAP) GrowableArray(10, true); - - _objarray_queue.initialize(); - _objarray_overflow_stack = - new (ResourceObj::C_HEAP) ObjArrayOverflowStack(10, true); - -#ifdef USE_RegionTaskQueueWithOverflow + _objarray_stack.initialize(); region_stack()->initialize(); -#else - region_stack()->initialize(); - - // We want the overflow stack to be permanent - _region_overflow_stack = - new (ResourceObj::C_HEAP) GrowableArray(10, true); -#endif // Note that _revisit_klass_stack is allocated out of the // C heap (as opposed to out of ResourceArena). @@ -71,12 +55,9 @@ // From some experiments (#klass/k)^2 for k = 10 seems a better fit, but this will // have to do for now until we are able to investigate a more optimal setting. _revisit_mdo_stack = new (ResourceObj::C_HEAP) GrowableArray(size*2, true); - } ParCompactionManager::~ParCompactionManager() { - delete _overflow_stack; - delete _objarray_overflow_stack; delete _revisit_klass_stack; delete _revisit_mdo_stack; // _manager_array and _stack_array are statics @@ -108,12 +89,8 @@ _manager_array[i] = new ParCompactionManager(); guarantee(_manager_array[i] != NULL, "Could not create ParCompactionManager"); stack_array()->register_queue(i, _manager_array[i]->marking_stack()); - _objarray_queues->register_queue(i, &_manager_array[i]->_objarray_queue); -#ifdef USE_RegionTaskQueueWithOverflow - region_array()->register_queue(i, _manager_array[i]->region_stack()->task_queue()); -#else + _objarray_queues->register_queue(i, &_manager_array[i]->_objarray_stack); region_array()->register_queue(i, _manager_array[i]->region_stack()); -#endif } // The VMThread gets its own ParCompactionManager, which is not available @@ -149,57 +126,6 @@ return action() == ParCompactionManager::ResetObjects; } -// For now save on a stack -void ParCompactionManager::save_for_scanning(oop m) { - stack_push(m); -} - -void ParCompactionManager::stack_push(oop obj) { - - if(!marking_stack()->push(obj)) { - overflow_stack()->push(obj); - } -} - -oop ParCompactionManager::retrieve_for_scanning() { - - // Should not be used in the parallel case - ShouldNotReachHere(); - return NULL; -} - -// Save region on a stack -void ParCompactionManager::save_for_processing(size_t region_index) { -#ifdef ASSERT - const ParallelCompactData& sd = PSParallelCompact::summary_data(); - ParallelCompactData::RegionData* const region_ptr = sd.region(region_index); - assert(region_ptr->claimed(), "must be claimed"); - assert(region_ptr->_pushed++ == 0, "should only be pushed once"); -#endif - region_stack_push(region_index); -} - -void ParCompactionManager::region_stack_push(size_t region_index) { - -#ifdef USE_RegionTaskQueueWithOverflow - region_stack()->save(region_index); -#else - if(!region_stack()->push(region_index)) { - region_overflow_stack()->push(region_index); - } -#endif -} - -bool ParCompactionManager::retrieve_for_processing(size_t& region_index) { -#ifdef USE_RegionTaskQueueWithOverflow - return region_stack()->retrieve(region_index); -#else - // Should not be used in the parallel case - ShouldNotReachHere(); - return false; -#endif -} - ParCompactionManager* ParCompactionManager::gc_thread_compaction_manager(int index) { assert(index >= 0 && index < (int)ParallelGCThreads, "index out of range"); @@ -218,8 +144,8 @@ do { // Drain the overflow stack first, to allow stealing from the marking stack. oop obj; - while (!overflow_stack()->is_empty()) { - overflow_stack()->pop()->follow_contents(this); + while (marking_stack()->pop_overflow(obj)) { + obj->follow_contents(this); } while (marking_stack()->pop_local(obj)) { obj->follow_contents(this); @@ -227,11 +153,10 @@ // Process ObjArrays one at a time to avoid marking stack bloat. ObjArrayTask task; - if (!_objarray_overflow_stack->is_empty()) { - task = _objarray_overflow_stack->pop(); + if (_objarray_stack.pop_overflow(task)) { objArrayKlass* const k = (objArrayKlass*)task.obj()->blueprint(); k->oop_follow_contents(this, task.obj(), task.index()); - } else if (_objarray_queue.pop_local(task)) { + } else if (_objarray_stack.pop_local(task)) { objArrayKlass* const k = (objArrayKlass*)task.obj()->blueprint(); k->oop_follow_contents(this, task.obj(), task.index()); } @@ -240,68 +165,18 @@ assert(marking_stacks_empty(), "Sanity"); } -void ParCompactionManager::drain_region_overflow_stack() { - size_t region_index = (size_t) -1; - while(region_stack()->retrieve_from_overflow(region_index)) { - PSParallelCompact::fill_and_update_region(this, region_index); - } -} - void ParCompactionManager::drain_region_stacks() { -#ifdef ASSERT - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - MutableSpace* to_space = heap->young_gen()->to_space(); - MutableSpace* old_space = heap->old_gen()->object_space(); - MutableSpace* perm_space = heap->perm_gen()->object_space(); -#endif /* ASSERT */ - -#if 1 // def DO_PARALLEL - the serial code hasn't been updated do { - -#ifdef USE_RegionTaskQueueWithOverflow - // Drain overflow stack first, so other threads can steal from - // claimed stack while we work. - size_t region_index = (size_t) -1; - while(region_stack()->retrieve_from_overflow(region_index)) { + // Drain overflow stack first so other threads can steal. + size_t region_index; + while (region_stack()->pop_overflow(region_index)) { PSParallelCompact::fill_and_update_region(this, region_index); } - while (region_stack()->retrieve_from_stealable_queue(region_index)) { + while (region_stack()->pop_local(region_index)) { PSParallelCompact::fill_and_update_region(this, region_index); } } while (!region_stack()->is_empty()); -#else - // Drain overflow stack first, so other threads can steal from - // claimed stack while we work. - while(!region_overflow_stack()->is_empty()) { - size_t region_index = region_overflow_stack()->pop(); - PSParallelCompact::fill_and_update_region(this, region_index); - } - - size_t region_index = -1; - // obj is a reference!!! - while (region_stack()->pop_local(region_index)) { - // It would be nice to assert about the type of objects we might - // pop, but they can come from anywhere, unfortunately. - PSParallelCompact::fill_and_update_region(this, region_index); - } - } while((region_stack()->size() != 0) || - (region_overflow_stack()->length() != 0)); -#endif - -#ifdef USE_RegionTaskQueueWithOverflow - assert(region_stack()->is_empty(), "Sanity"); -#else - assert(region_stack()->size() == 0, "Sanity"); - assert(region_overflow_stack()->length() == 0, "Sanity"); -#endif -#else - oop obj; - while (obj = retrieve_for_scanning()) { - obj->follow_contents(this); - } -#endif } #ifdef ASSERT diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,10 +59,10 @@ private: // 32-bit: 4K * 8 = 32KiB; 64-bit: 8K * 16 = 128KiB - #define OBJARRAY_QUEUE_SIZE (1 << NOT_LP64(12) LP64_ONLY(13)) - typedef GenericTaskQueue ObjArrayTaskQueue; - typedef GenericTaskQueueSet ObjArrayTaskQueueSet; - #undef OBJARRAY_QUEUE_SIZE + #define QUEUE_SIZE (1 << NOT_LP64(12) LP64_ONLY(13)) + typedef OverflowTaskQueue ObjArrayTaskQueue; + typedef GenericTaskQueueSet ObjArrayTaskQueueSet; + #undef QUEUE_SIZE static ParCompactionManager** _manager_array; static OopTaskQueueSet* _stack_array; @@ -72,23 +72,13 @@ static PSOldGen* _old_gen; private: - OopTaskQueue _marking_stack; - GrowableArray* _overflow_stack; - - typedef GrowableArray ObjArrayOverflowStack; - ObjArrayTaskQueue _objarray_queue; - ObjArrayOverflowStack* _objarray_overflow_stack; + OverflowTaskQueue _marking_stack; + ObjArrayTaskQueue _objarray_stack; // Is there a way to reuse the _marking_stack for the // saving empty regions? For now just create a different // type of TaskQueue. - -#ifdef USE_RegionTaskQueueWithOverflow - RegionTaskQueueWithOverflow _region_stack; -#else RegionTaskQueue _region_stack; - GrowableArray* _region_overflow_stack; -#endif #if 1 // does this happen enough to need a per thread stack? GrowableArray* _revisit_klass_stack; @@ -107,16 +97,8 @@ protected: // Array of tasks. Needed by the ParallelTaskTerminator. static RegionTaskQueueSet* region_array() { return _region_array; } - OopTaskQueue* marking_stack() { return &_marking_stack; } - GrowableArray* overflow_stack() { return _overflow_stack; } -#ifdef USE_RegionTaskQueueWithOverflow - RegionTaskQueueWithOverflow* region_stack() { return &_region_stack; } -#else - RegionTaskQueue* region_stack() { return &_region_stack; } - GrowableArray* region_overflow_stack() { - return _region_overflow_stack; - } -#endif + OverflowTaskQueue* marking_stack() { return &_marking_stack; } + RegionTaskQueue* region_stack() { return &_region_stack; } // Pushes onto the marking stack. If the marking stack is full, // pushes onto the overflow stack. @@ -124,11 +106,7 @@ // Do not implement an equivalent stack_pop. Deal with the // marking stack and overflow stack directly. - // Pushes onto the region stack. If the region stack is full, - // pushes onto the region overflow stack. - void region_stack_push(size_t region_index); - -public: + public: Action action() { return _action; } void set_action(Action v) { _action = v; } @@ -157,22 +135,15 @@ GrowableArray* revisit_mdo_stack() { return _revisit_mdo_stack; } #endif - // Save oop for later processing. Must not fail. - void save_for_scanning(oop m); - // Get a oop for scanning. If returns null, no oop were found. - oop retrieve_for_scanning(); - - inline void push_objarray(oop obj, size_t index); - - // Save region for later processing. Must not fail. - void save_for_processing(size_t region_index); - // Get a region for processing. If returns null, no region were found. - bool retrieve_for_processing(size_t& region_index); + // Save for later processing. Must not fail. + inline void push(oop obj) { _marking_stack.push(obj); } + inline void push_objarray(oop objarray, size_t index); + inline void push_region(size_t index); // Access function for compaction managers static ParCompactionManager* gc_thread_compaction_manager(int index); - static bool steal(int queue_num, int* seed, Task& t) { + static bool steal(int queue_num, int* seed, oop& t) { return stack_array()->steal(queue_num, seed, t); } @@ -180,8 +151,8 @@ return _objarray_queues->steal(queue_num, seed, t); } - static bool steal(int queue_num, int* seed, RegionTask& t) { - return region_array()->steal(queue_num, seed, t); + static bool steal(int queue_num, int* seed, size_t& region) { + return region_array()->steal(queue_num, seed, region); } // Process tasks remaining on any marking stack @@ -191,9 +162,6 @@ // Process tasks remaining on any stack void drain_region_stacks(); - // Process tasks remaining on any stack - void drain_region_overflow_stack(); - // Debugging support #ifdef ASSERT bool stacks_have_been_allocated(); @@ -208,6 +176,5 @@ } bool ParCompactionManager::marking_stacks_empty() const { - return _marking_stack.size() == 0 && _overflow_stack->is_empty() && - _objarray_queue.size() == 0 && _objarray_overflow_stack->is_empty(); + return _marking_stack.is_empty() && _objarray_stack.is_empty(); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -26,7 +26,16 @@ { ObjArrayTask task(obj, index); assert(task.is_valid(), "bad ObjArrayTask"); - if (!_objarray_queue.push(task)) { - _objarray_overflow_stack->push(task); - } + _objarray_stack.push(task); } + +void ParCompactionManager::push_region(size_t index) +{ +#ifdef ASSERT + const ParallelCompactData& sd = PSParallelCompact::summary_data(); + ParallelCompactData::RegionData* const region_ptr = sd.region(index); + assert(region_ptr->claimed(), "must be claimed"); + assert(region_ptr->_pushed++ == 0, "should only be pushed once"); +#endif + region_stack()->push(index); +} diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -2474,7 +2474,7 @@ for (size_t cur = end_region - 1; cur >= beg_region; --cur) { if (sd.region(cur)->claim_unsafe()) { ParCompactionManager* cm = ParCompactionManager::manager_array(which); - cm->save_for_processing(cur); + cm->push_region(cur); if (TraceParallelOldGCCompactionPhase && Verbose) { const size_t count_mod_8 = fillable_regions & 7; @@ -3138,7 +3138,7 @@ assert(cur->data_size() > 0, "region must have live data"); cur->decrement_destination_count(); if (cur < enqueue_end && cur->available() && cur->claim()) { - cm->save_for_processing(sd.region(cur)); + cm->push_region(sd.region(cur)); } } } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1297,11 +1297,8 @@ T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - if (mark_bitmap()->is_unmarked(obj)) { - if (mark_obj(obj)) { - // This thread marked the object and owns the subsequent processing of it. - cm->save_for_scanning(obj); - } + if (mark_bitmap()->is_unmarked(obj) && mark_obj(obj)) { + cm->push(obj); } } } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,45 +94,13 @@ print_stats(); #endif // PS_PM_STATS - for(uint i=0; ioverflow_stack_depth()->length() <= 0), - "promotion manager overflow stack must be empty"); - guarantee((UseDepthFirstScavengeOrder || - manager->overflow_stack_breadth()->length() <= 0), - "promotion manager overflow stack must be empty"); - - guarantee((!UseDepthFirstScavengeOrder || - manager->claimed_stack_depth()->size() <= 0), - "promotion manager claimed stack must be empty"); - guarantee((UseDepthFirstScavengeOrder || - manager->claimed_stack_breadth()->size() <= 0), - "promotion manager claimed stack must be empty"); + if (UseDepthFirstScavengeOrder) { + assert(manager->claimed_stack_depth()->is_empty(), "should be empty"); } else { - guarantee((!UseDepthFirstScavengeOrder || - manager->overflow_stack_depth()->length() <= 0), - "VM Thread promotion manager overflow stack " - "must be empty"); - guarantee((UseDepthFirstScavengeOrder || - manager->overflow_stack_breadth()->length() <= 0), - "VM Thread promotion manager overflow stack " - "must be empty"); - - guarantee((!UseDepthFirstScavengeOrder || - manager->claimed_stack_depth()->size() <= 0), - "VM Thread promotion manager claimed stack " - "must be empty"); - guarantee((UseDepthFirstScavengeOrder || - manager->claimed_stack_breadth()->size() <= 0), - "VM Thread promotion manager claimed stack " - "must be empty"); + assert(manager->claimed_stack_breadth()->is_empty(), "should be empty"); } - manager->flush_labs(); } } @@ -181,15 +149,9 @@ if (depth_first()) { claimed_stack_depth()->initialize(); queue_size = claimed_stack_depth()->max_elems(); - // We want the overflow stack to be permanent - _overflow_stack_depth = new (ResourceObj::C_HEAP) GrowableArray(10, true); - _overflow_stack_breadth = NULL; } else { claimed_stack_breadth()->initialize(); queue_size = claimed_stack_breadth()->max_elems(); - // We want the overflow stack to be permanent - _overflow_stack_breadth = new (ResourceObj::C_HEAP) GrowableArray(10, true); - _overflow_stack_depth = NULL; } _totally_drain = (ParallelGCThreads == 1) || (GCDrainStackTargetSize == 0); @@ -209,8 +171,7 @@ } void PSPromotionManager::reset() { - assert(claimed_stack_empty(), "reset of non-empty claimed stack"); - assert(overflow_stack_empty(), "reset of non-empty overflow stack"); + assert(stacks_empty(), "reset of non-empty stack"); // We need to get an assert in here to make sure the labs are always flushed. @@ -243,7 +204,7 @@ void PSPromotionManager::drain_stacks_depth(bool totally_drain) { assert(depth_first(), "invariant"); - assert(overflow_stack_depth() != NULL, "invariant"); + assert(claimed_stack_depth()->overflow_stack() != NULL, "invariant"); totally_drain = totally_drain || _totally_drain; #ifdef ASSERT @@ -254,41 +215,35 @@ MutableSpace* perm_space = heap->perm_gen()->object_space(); #endif /* ASSERT */ + OopStarTaskQueue* const tq = claimed_stack_depth(); do { StarTask p; // Drain overflow stack first, so other threads can steal from // claimed stack while we work. - while(!overflow_stack_depth()->is_empty()) { - // linux compiler wants different overloaded operator= in taskqueue to - // assign to p that the other compilers don't like. - StarTask ptr = overflow_stack_depth()->pop(); - process_popped_location_depth(ptr); + while (tq->pop_overflow(p)) { + process_popped_location_depth(p); } if (totally_drain) { - while (claimed_stack_depth()->pop_local(p)) { + while (tq->pop_local(p)) { process_popped_location_depth(p); } } else { - while (claimed_stack_depth()->size() > _target_stack_size && - claimed_stack_depth()->pop_local(p)) { + while (tq->size() > _target_stack_size && tq->pop_local(p)) { process_popped_location_depth(p); } } - } while( (totally_drain && claimed_stack_depth()->size() > 0) || - (overflow_stack_depth()->length() > 0) ); + } while (totally_drain && !tq->taskqueue_empty() || !tq->overflow_empty()); - assert(!totally_drain || claimed_stack_empty(), "Sanity"); - assert(totally_drain || - claimed_stack_depth()->size() <= _target_stack_size, - "Sanity"); - assert(overflow_stack_empty(), "Sanity"); + assert(!totally_drain || tq->taskqueue_empty(), "Sanity"); + assert(totally_drain || tq->size() <= _target_stack_size, "Sanity"); + assert(tq->overflow_empty(), "Sanity"); } void PSPromotionManager::drain_stacks_breadth(bool totally_drain) { assert(!depth_first(), "invariant"); - assert(overflow_stack_breadth() != NULL, "invariant"); + assert(claimed_stack_breadth()->overflow_stack() != NULL, "invariant"); totally_drain = totally_drain || _totally_drain; #ifdef ASSERT @@ -299,51 +254,39 @@ MutableSpace* perm_space = heap->perm_gen()->object_space(); #endif /* ASSERT */ + OverflowTaskQueue* const tq = claimed_stack_breadth(); do { oop obj; // Drain overflow stack first, so other threads can steal from // claimed stack while we work. - while(!overflow_stack_breadth()->is_empty()) { - obj = overflow_stack_breadth()->pop(); + while (tq->pop_overflow(obj)) { obj->copy_contents(this); } if (totally_drain) { - // obj is a reference!!! - while (claimed_stack_breadth()->pop_local(obj)) { - // It would be nice to assert about the type of objects we might - // pop, but they can come from anywhere, unfortunately. + while (tq->pop_local(obj)) { obj->copy_contents(this); } } else { - // obj is a reference!!! - while (claimed_stack_breadth()->size() > _target_stack_size && - claimed_stack_breadth()->pop_local(obj)) { - // It would be nice to assert about the type of objects we might - // pop, but they can come from anywhere, unfortunately. + while (tq->size() > _target_stack_size && tq->pop_local(obj)) { obj->copy_contents(this); } } // If we could not find any other work, flush the prefetch queue - if (claimed_stack_breadth()->size() == 0 && - (overflow_stack_breadth()->length() == 0)) { + if (tq->is_empty()) { flush_prefetch_queue(); } - } while((totally_drain && claimed_stack_breadth()->size() > 0) || - (overflow_stack_breadth()->length() > 0)); + } while (totally_drain && !tq->taskqueue_empty() || !tq->overflow_empty()); - assert(!totally_drain || claimed_stack_empty(), "Sanity"); - assert(totally_drain || - claimed_stack_breadth()->size() <= _target_stack_size, - "Sanity"); - assert(overflow_stack_empty(), "Sanity"); + assert(!totally_drain || tq->taskqueue_empty(), "Sanity"); + assert(totally_drain || tq->size() <= _target_stack_size, "Sanity"); + assert(tq->overflow_empty(), "Sanity"); } void PSPromotionManager::flush_labs() { - assert(claimed_stack_empty(), "Attempt to flush lab with live stack"); - assert(overflow_stack_empty(), "Attempt to flush lab with live overflow stack"); + assert(stacks_empty(), "Attempt to flush lab with live stack"); // If either promotion lab fills up, we can flush the // lab but not refill it, so check first. diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,9 +78,7 @@ PrefetchQueue _prefetch_queue; OopStarTaskQueue _claimed_stack_depth; - GrowableArray* _overflow_stack_depth; - OopTaskQueue _claimed_stack_breadth; - GrowableArray* _overflow_stack_breadth; + OverflowTaskQueue _claimed_stack_breadth; bool _depth_first; bool _totally_drain; @@ -97,9 +95,6 @@ template inline void claim_or_forward_internal_depth(T* p); template inline void claim_or_forward_internal_breadth(T* p); - GrowableArray* overflow_stack_depth() { return _overflow_stack_depth; } - GrowableArray* overflow_stack_breadth() { return _overflow_stack_breadth; } - // On the task queues we push reference locations as well as // partially-scanned arrays (in the latter case, we push an oop to // the from-space image of the array and the length on the @@ -151,18 +146,19 @@ #if PS_PM_STATS ++_total_pushes; + int stack_length = claimed_stack_depth()->overflow_stack()->length(); #endif // PS_PM_STATS - if (!claimed_stack_depth()->push(p)) { - overflow_stack_depth()->push(p); + claimed_stack_depth()->push(p); + #if PS_PM_STATS + if (claimed_stack_depth()->overflow_stack()->length() != stack_length) { ++_overflow_pushes; - uint stack_length = (uint) overflow_stack_depth()->length(); - if (stack_length > _max_overflow_length) { - _max_overflow_length = stack_length; + if ((uint)stack_length + 1 > _max_overflow_length) { + _max_overflow_length = (uint)stack_length + 1; } + } #endif // PS_PM_STATS - } } void push_breadth(oop o) { @@ -170,18 +166,19 @@ #if PS_PM_STATS ++_total_pushes; + int stack_length = claimed_stack_breadth()->overflow_stack()->length(); #endif // PS_PM_STATS - if(!claimed_stack_breadth()->push(o)) { - overflow_stack_breadth()->push(o); + claimed_stack_breadth()->push(o); + #if PS_PM_STATS + if (claimed_stack_breadth()->overflow_stack()->length() != stack_length) { ++_overflow_pushes; - uint stack_length = (uint) overflow_stack_breadth()->length(); - if (stack_length > _max_overflow_length) { - _max_overflow_length = stack_length; + if ((uint)stack_length + 1 > _max_overflow_length) { + _max_overflow_length = (uint)stack_length + 1; } + } #endif // PS_PM_STATS - } } protected: @@ -199,12 +196,10 @@ static PSPromotionManager* vm_thread_promotion_manager(); static bool steal_depth(int queue_num, int* seed, StarTask& t) { - assert(stack_array_depth() != NULL, "invariant"); return stack_array_depth()->steal(queue_num, seed, t); } - static bool steal_breadth(int queue_num, int* seed, Task& t) { - assert(stack_array_breadth() != NULL, "invariant"); + static bool steal_breadth(int queue_num, int* seed, oop& t) { return stack_array_breadth()->steal(queue_num, seed, t); } @@ -214,7 +209,7 @@ OopStarTaskQueue* claimed_stack_depth() { return &_claimed_stack_depth; } - OopTaskQueue* claimed_stack_breadth() { + OverflowTaskQueue* claimed_stack_breadth() { return &_claimed_stack_breadth; } @@ -246,25 +241,13 @@ void drain_stacks_depth(bool totally_drain); void drain_stacks_breadth(bool totally_drain); - bool claimed_stack_empty() { - if (depth_first()) { - return claimed_stack_depth()->size() <= 0; - } else { - return claimed_stack_breadth()->size() <= 0; - } - } - bool overflow_stack_empty() { - if (depth_first()) { - return overflow_stack_depth()->length() <= 0; - } else { - return overflow_stack_breadth()->length() <= 0; - } + bool depth_first() const { + return _depth_first; } bool stacks_empty() { - return claimed_stack_empty() && overflow_stack_empty(); - } - bool depth_first() { - return _depth_first; + return depth_first() ? + claimed_stack_depth()->is_empty() : + claimed_stack_breadth()->is_empty(); } inline void process_popped_location_depth(StarTask p); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -414,7 +414,6 @@ } // Finally, flush the promotion_manager's labs, and deallocate its stacks. - assert(promotion_manager->claimed_stack_empty(), "Sanity"); PSPromotionManager::post_scavenge(); promotion_failure_occurred = promotion_failed(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/includeDB_compiler2 --- a/hotspot/src/share/vm/includeDB_compiler2 Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/includeDB_compiler2 Wed Jul 05 17:18:12 2017 +0200 @@ -89,6 +89,21 @@ allocation.hpp c2_globals.hpp +bcEscapeAnalyzer.cpp bcEscapeAnalyzer.hpp +bcEscapeAnalyzer.cpp bitMap.inline.hpp +bcEscapeAnalyzer.cpp bytecode.hpp +bcEscapeAnalyzer.cpp ciConstant.hpp +bcEscapeAnalyzer.cpp ciField.hpp +bcEscapeAnalyzer.cpp ciMethodBlocks.hpp +bcEscapeAnalyzer.cpp ciStreams.hpp + +bcEscapeAnalyzer.hpp allocation.hpp +bcEscapeAnalyzer.hpp ciMethod.hpp +bcEscapeAnalyzer.hpp ciMethodData.hpp +bcEscapeAnalyzer.hpp dependencies.hpp +bcEscapeAnalyzer.hpp growableArray.hpp +bcEscapeAnalyzer.hpp vectset.hpp + block.cpp allocation.inline.hpp block.cpp block.hpp block.cpp cfgnode.hpp @@ -239,6 +254,7 @@ ciEnv.cpp compileLog.hpp ciEnv.cpp runtime.hpp +ciMethod.cpp bcEscapeAnalyzer.hpp ciMethod.cpp ciTypeFlow.hpp ciMethod.cpp methodOop.hpp diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/includeDB_core --- a/hotspot/src/share/vm/includeDB_core Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/includeDB_core Wed Jul 05 17:18:12 2017 +0200 @@ -301,20 +301,6 @@ barrierSet.inline.hpp barrierSet.hpp barrierSet.inline.hpp cardTableModRefBS.hpp -bcEscapeAnalyzer.cpp bcEscapeAnalyzer.hpp -bcEscapeAnalyzer.cpp bitMap.inline.hpp -bcEscapeAnalyzer.cpp bytecode.hpp -bcEscapeAnalyzer.cpp ciConstant.hpp -bcEscapeAnalyzer.cpp ciField.hpp -bcEscapeAnalyzer.cpp ciMethodBlocks.hpp -bcEscapeAnalyzer.cpp ciStreams.hpp - -bcEscapeAnalyzer.hpp allocation.hpp -bcEscapeAnalyzer.hpp ciMethod.hpp -bcEscapeAnalyzer.hpp ciMethodData.hpp -bcEscapeAnalyzer.hpp dependencies.hpp -bcEscapeAnalyzer.hpp growableArray.hpp - biasedLocking.cpp biasedLocking.hpp biasedLocking.cpp klass.inline.hpp biasedLocking.cpp markOop.hpp @@ -545,6 +531,7 @@ ciCPCache.hpp ciClassList.hpp ciCPCache.hpp ciObject.hpp +ciCPCache.hpp cpCacheOop.hpp ciEnv.cpp allocation.inline.hpp ciEnv.cpp ciConstant.hpp @@ -664,7 +651,6 @@ ciMethod.cpp abstractCompiler.hpp ciMethod.cpp allocation.inline.hpp -ciMethod.cpp bcEscapeAnalyzer.hpp ciMethod.cpp bitMap.inline.hpp ciMethod.cpp ciCallProfile.hpp ciMethod.cpp ciExceptionHandler.hpp @@ -823,6 +809,7 @@ ciStreams.cpp ciCallSite.hpp ciStreams.cpp ciConstant.hpp +ciStreams.cpp ciCPCache.hpp ciStreams.cpp ciField.hpp ciStreams.cpp ciStreams.hpp ciStreams.cpp ciUtilities.hpp @@ -962,7 +949,6 @@ classLoader.cpp timer.hpp classLoader.cpp universe.inline.hpp classLoader.cpp vmSymbols.hpp -classLoader.cpp vtune.hpp classLoader.hpp classFileParser.hpp classLoader.hpp perfData.hpp @@ -1002,7 +988,6 @@ codeBlob.cpp safepoint.hpp codeBlob.cpp sharedRuntime.hpp codeBlob.cpp vframe.hpp -codeBlob.cpp vtune.hpp codeBlob.hpp codeBuffer.hpp codeBlob.hpp frame.hpp @@ -2165,7 +2150,6 @@ interpreter.cpp stubRoutines.hpp interpreter.cpp templateTable.hpp interpreter.cpp timer.hpp -interpreter.cpp vtune.hpp interpreter.hpp cppInterpreter.hpp interpreter.hpp stubs.hpp @@ -2321,7 +2305,6 @@ java.cpp vmError.hpp java.cpp vm_operations.hpp java.cpp vm_version_.hpp -java.cpp vtune.hpp java.hpp os.hpp @@ -3048,7 +3031,6 @@ nmethod.cpp scopeDesc.hpp nmethod.cpp sharedRuntime.hpp nmethod.cpp sweeper.hpp -nmethod.cpp vtune.hpp nmethod.cpp xmlstream.hpp nmethod.hpp codeBlob.hpp @@ -3771,7 +3753,6 @@ sharedRuntime.cpp vmSymbols.hpp sharedRuntime.cpp vmreg_.inline.hpp sharedRuntime.cpp vtableStubs.hpp -sharedRuntime.cpp vtune.hpp sharedRuntime.cpp xmlstream.hpp sharedRuntime.hpp allocation.hpp @@ -3935,7 +3916,6 @@ stubCodeGenerator.cpp forte.hpp stubCodeGenerator.cpp oop.inline.hpp stubCodeGenerator.cpp stubCodeGenerator.hpp -stubCodeGenerator.cpp vtune.hpp stubCodeGenerator.hpp allocation.hpp stubCodeGenerator.hpp assembler.hpp @@ -4456,7 +4436,6 @@ universe.cpp universe.inline.hpp universe.cpp vmSymbols.hpp universe.cpp vm_operations.hpp -universe.cpp vtune.hpp universe.hpp growableArray.hpp universe.hpp handles.hpp @@ -4719,7 +4698,6 @@ vtableStubs.cpp resourceArea.hpp vtableStubs.cpp sharedRuntime.hpp vtableStubs.cpp vtableStubs.hpp -vtableStubs.cpp vtune.hpp vtableStubs.hpp allocation.hpp @@ -4733,11 +4711,6 @@ vtableStubs_.cpp vmreg_.inline.hpp vtableStubs_.cpp vtableStubs.hpp -vtune.hpp allocation.hpp - -vtune_.cpp interpreter.hpp -vtune_.cpp vtune.hpp - watermark.hpp allocation.hpp watermark.hpp globalDefinitions.hpp diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/bytecode.cpp --- a/hotspot/src/share/vm/interpreter/bytecode.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/bytecode.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -136,25 +136,24 @@ // Implementation of Bytecode_invoke void Bytecode_invoke::verify() const { - Bytecodes::Code bc = adjusted_invoke_code(); assert(is_valid(), "check invoke"); assert(method()->constants()->cache() != NULL, "do not call this from verifier or rewriter"); } -symbolOop Bytecode_invoke::signature() const { +symbolOop Bytecode_member_ref::signature() const { constantPoolOop constants = method()->constants(); return constants->signature_ref_at(index()); } -symbolOop Bytecode_invoke::name() const { +symbolOop Bytecode_member_ref::name() const { constantPoolOop constants = method()->constants(); return constants->name_ref_at(index()); } -BasicType Bytecode_invoke::result_type(Thread *thread) const { +BasicType Bytecode_member_ref::result_type(Thread *thread) const { symbolHandle sh(thread, signature()); ResultTypeFinder rts(sh); rts.iterate(); @@ -167,9 +166,9 @@ KlassHandle resolved_klass; constantPoolHandle constants(THREAD, _method->constants()); - if (adjusted_invoke_code() == Bytecodes::_invokedynamic) { + if (java_code() == Bytecodes::_invokedynamic) { LinkResolver::resolve_dynamic_method(m, resolved_klass, constants, index(), CHECK_(methodHandle())); - } else if (adjusted_invoke_code() != Bytecodes::_invokeinterface) { + } else if (java_code() != Bytecodes::_invokeinterface) { LinkResolver::resolve_method(m, resolved_klass, constants, index(), CHECK_(methodHandle())); } else { LinkResolver::resolve_interface_method(m, resolved_klass, constants, index(), CHECK_(methodHandle())); @@ -178,51 +177,68 @@ } -int Bytecode_invoke::index() const { +int Bytecode_member_ref::index() const { // Note: Rewriter::rewrite changes the Java_u2 of an invokedynamic to a native_u4, // at the same time it allocates per-call-site CP cache entries. - Bytecodes::Code stdc = Bytecodes::java_code(code()); - Bytecode* invoke = Bytecode_at(bcp()); - if (invoke->has_index_u4(stdc)) - return invoke->get_index_u4(stdc); + Bytecodes::Code rawc = code(); + Bytecode* invoke = bytecode(); + if (invoke->has_index_u4(rawc)) + return invoke->get_index_u4(rawc); else - return invoke->get_index_u2_cpcache(stdc); + return invoke->get_index_u2_cpcache(rawc); } +int Bytecode_member_ref::pool_index() const { + int index = this->index(); + DEBUG_ONLY({ + if (!bytecode()->has_index_u4(code())) + index -= constantPoolOopDesc::CPCACHE_INDEX_TAG; + }); + return _method->constants()->cache()->entry_at(index)->constant_pool_index(); +} // Implementation of Bytecode_field void Bytecode_field::verify() const { - Bytecodes::Code stdc = Bytecodes::java_code(code()); - assert(stdc == Bytecodes::_putstatic || stdc == Bytecodes::_getstatic || - stdc == Bytecodes::_putfield || stdc == Bytecodes::_getfield, "check field"); -} - - -bool Bytecode_field::is_static() const { - Bytecodes::Code stdc = Bytecodes::java_code(code()); - return stdc == Bytecodes::_putstatic || stdc == Bytecodes::_getstatic; + assert(is_valid(), "check field"); } -int Bytecode_field::index() const { - Bytecode* invoke = Bytecode_at(bcp()); - return invoke->get_index_u2_cpcache(Bytecodes::_getfield); +// Implementation of Bytecode_loadconstant + +int Bytecode_loadconstant::raw_index() const { + Bytecode* bcp = bytecode(); + Bytecodes::Code rawc = bcp->code(); + assert(rawc != Bytecodes::_wide, "verifier prevents this"); + if (Bytecodes::java_code(rawc) == Bytecodes::_ldc) + return bcp->get_index_u1(rawc); + else + return bcp->get_index_u2(rawc, false); } - -// Implementation of Bytecodes loac constant +int Bytecode_loadconstant::pool_index() const { + int index = raw_index(); + if (has_cache_index()) { + return _method->constants()->cache()->entry_at(index)->constant_pool_index(); + } + return index; +} -int Bytecode_loadconstant::index() const { - Bytecodes::Code stdc = Bytecodes::java_code(code()); - if (stdc != Bytecodes::_wide) { - if (Bytecodes::java_code(stdc) == Bytecodes::_ldc) - return get_index_u1(stdc); - else - return get_index_u2(stdc, false); +BasicType Bytecode_loadconstant::result_type() const { + int index = pool_index(); + constantTag tag = _method->constants()->tag_at(index); + return tag.basic_type(); +} + +oop Bytecode_loadconstant::resolve_constant(TRAPS) const { + assert(_method.not_null(), "must supply method to resolve constant"); + int index = raw_index(); + constantPoolOop constants = _method->constants(); + if (has_cache_index()) { + return constants->resolve_cached_constant_at(index, THREAD); + } else { + return constants->resolve_constant_at(index, THREAD); } - stdc = Bytecodes::code_at(addr_at(1)); - return get_index_u2(stdc, true); } //------------------------------------------------------------------------------ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/bytecode.hpp --- a/hotspot/src/share/vm/interpreter/bytecode.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/bytecode.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -76,9 +76,13 @@ return Bytes::get_native_u2(p); else return Bytes::get_Java_u2(p); } + int get_index_u1_cpcache(Bytecodes::Code bc) const { + assert_same_format_as(bc); assert_index_size(1, bc); + return *(jubyte*)addr_at(1) + constantPoolOopDesc::CPCACHE_INDEX_TAG; + } int get_index_u2_cpcache(Bytecodes::Code bc) const { assert_same_format_as(bc); assert_index_size(2, bc); assert_native_index(bc); - return Bytes::get_native_u2(addr_at(1)) DEBUG_ONLY(+ constantPoolOopDesc::CPCACHE_INDEX_TAG); + return Bytes::get_native_u2(addr_at(1)) + constantPoolOopDesc::CPCACHE_INDEX_TAG; } int get_index_u4(Bytecodes::Code bc) const { assert_same_format_as(bc); assert_index_size(4, bc); @@ -152,7 +156,7 @@ inline Bytecode_lookupswitch* Bytecode_lookupswitch_at(address bcp) { Bytecode_lookupswitch* b = (Bytecode_lookupswitch*)bcp; - debug_only(b->verify()); + DEBUG_ONLY(b->verify()); return b; } @@ -174,44 +178,56 @@ inline Bytecode_tableswitch* Bytecode_tableswitch_at(address bcp) { Bytecode_tableswitch* b = (Bytecode_tableswitch*)bcp; - debug_only(b->verify()); + DEBUG_ONLY(b->verify()); return b; } -// Abstraction for invoke_{virtual, static, interface, special} +// Common code for decoding invokes and field references. -class Bytecode_invoke: public ResourceObj { +class Bytecode_member_ref: public ResourceObj { protected: methodHandle _method; // method containing the bytecode int _bci; // position of the bytecode - Bytecode_invoke(methodHandle method, int bci) : _method(method), _bci(bci) {} + Bytecode_member_ref(methodHandle method, int bci) : _method(method), _bci(bci) {} + + public: + // Attributes + methodHandle method() const { return _method; } + int bci() const { return _bci; } + address bcp() const { return _method->bcp_from(bci()); } + Bytecode* bytecode() const { return Bytecode_at(bcp()); } + + int index() const; // cache index (loaded from instruction) + int pool_index() const; // constant pool index + symbolOop name() const; // returns the name of the method or field + symbolOop signature() const; // returns the signature of the method or field + + BasicType result_type(Thread* thread) const; // returns the result type of the getfield or invoke + + Bytecodes::Code code() const { return Bytecodes::code_at(bcp(), _method()); } + Bytecodes::Code java_code() const { return Bytecodes::java_code(code()); } +}; + +// Abstraction for invoke_{virtual, static, interface, special} + +class Bytecode_invoke: public Bytecode_member_ref { + protected: + Bytecode_invoke(methodHandle method, int bci) : Bytecode_member_ref(method, bci) {} public: void verify() const; // Attributes - methodHandle method() const { return _method; } - int bci() const { return _bci; } - address bcp() const { return _method->bcp_from(bci()); } - - int index() const; // the constant pool index for the invoke - symbolOop name() const; // returns the name of the invoked method - symbolOop signature() const; // returns the signature of the invoked method - BasicType result_type(Thread *thread) const; // returns the result type of the invoke - - Bytecodes::Code code() const { return Bytecodes::code_at(bcp(), _method()); } - Bytecodes::Code adjusted_invoke_code() const { return Bytecodes::java_code(code()); } - methodHandle static_target(TRAPS); // "specified" method (from constant pool) // Testers - bool is_invokeinterface() const { return adjusted_invoke_code() == Bytecodes::_invokeinterface; } - bool is_invokevirtual() const { return adjusted_invoke_code() == Bytecodes::_invokevirtual; } - bool is_invokestatic() const { return adjusted_invoke_code() == Bytecodes::_invokestatic; } - bool is_invokespecial() const { return adjusted_invoke_code() == Bytecodes::_invokespecial; } - bool is_invokedynamic() const { return adjusted_invoke_code() == Bytecodes::_invokedynamic; } + bool is_invokeinterface() const { return java_code() == Bytecodes::_invokeinterface; } + bool is_invokevirtual() const { return java_code() == Bytecodes::_invokevirtual; } + bool is_invokestatic() const { return java_code() == Bytecodes::_invokestatic; } + bool is_invokespecial() const { return java_code() == Bytecodes::_invokespecial; } + bool is_invokedynamic() const { return java_code() == Bytecodes::_invokedynamic; } bool has_receiver() const { return !is_invokestatic() && !is_invokedynamic(); } @@ -230,7 +246,7 @@ inline Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci) { Bytecode_invoke* b = new Bytecode_invoke(method, bci); - debug_only(b->verify()); + DEBUG_ONLY(b->verify()); return b; } @@ -240,21 +256,34 @@ } -// Abstraction for all field accesses (put/get field/static_ -class Bytecode_field: public Bytecode { -public: +// Abstraction for all field accesses (put/get field/static) +class Bytecode_field: public Bytecode_member_ref { + protected: + Bytecode_field(methodHandle method, int bci) : Bytecode_member_ref(method, bci) {} + + public: + // Testers + bool is_getfield() const { return java_code() == Bytecodes::_getfield; } + bool is_putfield() const { return java_code() == Bytecodes::_putfield; } + bool is_getstatic() const { return java_code() == Bytecodes::_getstatic; } + bool is_putstatic() const { return java_code() == Bytecodes::_putstatic; } + + bool is_getter() const { return is_getfield() || is_getstatic(); } + bool is_static() const { return is_getstatic() || is_putstatic(); } + + bool is_valid() const { return is_getfield() || + is_putfield() || + is_getstatic() || + is_putstatic(); } void verify() const; - int index() const; - bool is_static() const; - // Creation - inline friend Bytecode_field* Bytecode_field_at(const methodOop method, address bcp); + inline friend Bytecode_field* Bytecode_field_at(methodHandle method, int bci); }; -inline Bytecode_field* Bytecode_field_at(const methodOop method, address bcp) { - Bytecode_field* b = (Bytecode_field*)bcp; - debug_only(b->verify()); +inline Bytecode_field* Bytecode_field_at(methodHandle method, int bci) { + Bytecode_field* b = new Bytecode_field(method, bci); + DEBUG_ONLY(b->verify()); return b; } @@ -274,7 +303,7 @@ inline Bytecode_checkcast* Bytecode_checkcast_at(address bcp) { Bytecode_checkcast* b = (Bytecode_checkcast*)bcp; - debug_only(b->verify()); + DEBUG_ONLY(b->verify()); return b; } @@ -294,7 +323,7 @@ inline Bytecode_instanceof* Bytecode_instanceof_at(address bcp) { Bytecode_instanceof* b = (Bytecode_instanceof*)bcp; - debug_only(b->verify()); + DEBUG_ONLY(b->verify()); return b; } @@ -312,7 +341,7 @@ inline Bytecode_new* Bytecode_new_at(address bcp) { Bytecode_new* b = (Bytecode_new*)bcp; - debug_only(b->verify()); + DEBUG_ONLY(b->verify()); return b; } @@ -330,7 +359,7 @@ inline Bytecode_multianewarray* Bytecode_multianewarray_at(address bcp) { Bytecode_multianewarray* b = (Bytecode_multianewarray*)bcp; - debug_only(b->verify()); + DEBUG_ONLY(b->verify()); return b; } @@ -348,29 +377,57 @@ inline Bytecode_anewarray* Bytecode_anewarray_at(address bcp) { Bytecode_anewarray* b = (Bytecode_anewarray*)bcp; - debug_only(b->verify()); + DEBUG_ONLY(b->verify()); return b; } // Abstraction for ldc, ldc_w and ldc2_w -class Bytecode_loadconstant: public Bytecode { +class Bytecode_loadconstant: public ResourceObj { + private: + int _bci; + methodHandle _method; + + Bytecodes::Code code() const { return bytecode()->code(); } + + int raw_index() const; + + Bytecode_loadconstant(methodHandle method, int bci) : _method(method), _bci(bci) {} + public: + // Attributes + methodHandle method() const { return _method; } + int bci() const { return _bci; } + address bcp() const { return _method->bcp_from(bci()); } + Bytecode* bytecode() const { return Bytecode_at(bcp()); } + void verify() const { + assert(_method.not_null(), "must supply method"); Bytecodes::Code stdc = Bytecodes::java_code(code()); assert(stdc == Bytecodes::_ldc || stdc == Bytecodes::_ldc_w || stdc == Bytecodes::_ldc2_w, "load constant"); } - int index() const; + // Only non-standard bytecodes (fast_aldc) have CP cache indexes. + bool has_cache_index() const { return code() >= Bytecodes::number_of_java_codes; } - inline friend Bytecode_loadconstant* Bytecode_loadconstant_at(const methodOop method, address bcp); + int pool_index() const; // index into constant pool + int cache_index() const { // index into CP cache (or -1 if none) + return has_cache_index() ? raw_index() : -1; + } + + BasicType result_type() const; // returns the result type of the ldc + + oop resolve_constant(TRAPS) const; + + // Creation + inline friend Bytecode_loadconstant* Bytecode_loadconstant_at(methodHandle method, int bci); }; -inline Bytecode_loadconstant* Bytecode_loadconstant_at(const methodOop method, address bcp) { - Bytecode_loadconstant* b = (Bytecode_loadconstant*)bcp; - debug_only(b->verify()); +inline Bytecode_loadconstant* Bytecode_loadconstant_at(methodHandle method, int bci) { + Bytecode_loadconstant* b = new Bytecode_loadconstant(method, bci); + DEBUG_ONLY(b->verify()); return b; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/bytecodeTracer.cpp --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -49,6 +49,7 @@ int get_index_u1() { return *(address)_next_pc++; } int get_index_u2() { int i=Bytes::get_Java_u2(_next_pc); _next_pc+=2; return i; } + int get_index_u1_cpcache() { return get_index_u1() + constantPoolOopDesc::CPCACHE_INDEX_TAG; } int get_index_u2_cpcache() { int i=Bytes::get_native_u2(_next_pc); _next_pc+=2; return i + constantPoolOopDesc::CPCACHE_INDEX_TAG; } int get_index_u4() { int i=Bytes::get_native_u4(_next_pc); _next_pc+=4; return i; } int get_index_special() { return (is_wide()) ? get_index_u2() : get_index_u1(); } @@ -60,6 +61,7 @@ bool check_index(int i, int& cp_index, outputStream* st = tty); void print_constant(int i, outputStream* st = tty); void print_field_or_method(int i, outputStream* st = tty); + void print_field_or_method(int orig_i, int i, outputStream* st = tty); void print_attributes(int bci, outputStream* st = tty); void bytecode_epilog(int bci, outputStream* st = tty); @@ -177,18 +179,29 @@ _closure->trace(method, bcp, st); } +void print_symbol(symbolOop sym, outputStream* st) { + char buf[40]; + int len = sym->utf8_length(); + if (len >= (int)sizeof(buf)) { + st->print_cr(" %s...[%d]", sym->as_C_string(buf, sizeof(buf)), len); + } else { + st->print(" "); + sym->print_on(st); st->cr(); + } +} + void print_oop(oop value, outputStream* st) { if (value == NULL) { st->print_cr(" NULL"); - } else { + } else if (java_lang_String::is_instance(value)) { EXCEPTION_MARK; Handle h_value (THREAD, value); symbolHandle sym = java_lang_String::as_symbol(h_value, CATCH); - if (sym->utf8_length() > 32) { - st->print_cr(" ...."); - } else { - sym->print_on(st); st->cr(); - } + print_symbol(sym(), st); + } else if (value->is_symbol()) { + print_symbol(symbolOop(value), st); + } else { + st->print_cr(" " PTR_FORMAT, (intptr_t) value); } } @@ -279,16 +292,27 @@ } else if (tag.is_double()) { st->print_cr(" %f", constants->double_at(i)); } else if (tag.is_string()) { - oop string = constants->resolved_string_at(i); + oop string = constants->pseudo_string_at(i); print_oop(string, st); } else if (tag.is_unresolved_string()) { - st->print_cr(" ", i); + const char* string = constants->string_at_noresolve(i); + st->print_cr(" %s", string); } else if (tag.is_klass()) { st->print_cr(" %s", constants->resolved_klass_at(i)->klass_part()->external_name()); } else if (tag.is_unresolved_klass()) { st->print_cr(" ", i); } else if (tag.is_object()) { - st->print_cr(" " PTR_FORMAT, constants->object_at(i)); + st->print(" "); + print_oop(constants->object_at(i), st); + } else if (tag.is_method_type()) { + int i2 = constants->method_type_index_at(i); + st->print(" %d", i2); + print_oop(constants->symbol_at(i2), st); + } else if (tag.is_method_handle()) { + int kind = constants->method_handle_ref_kind_at(i); + int i2 = constants->method_handle_index_at(i); + st->print(" ", kind, i2); + print_field_or_method(-i, i2, st); } else { st->print_cr(" bad tag=%d at %d", tag.value(), i); } @@ -297,7 +321,10 @@ void BytecodePrinter::print_field_or_method(int i, outputStream* st) { int orig_i = i; if (!check_index(orig_i, i, st)) return; + print_field_or_method(orig_i, i, st); +} +void BytecodePrinter::print_field_or_method(int orig_i, int i, outputStream* st) { constantPoolOop constants = method()->constants(); constantTag tag = constants->tag_at(i); @@ -314,9 +341,11 @@ return; } + symbolOop klass = constants->klass_name_at(constants->uncached_klass_ref_index_at(i)); symbolOop name = constants->uncached_name_ref_at(i); symbolOop signature = constants->uncached_signature_ref_at(i); - st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string()); + const char* sep = (tag.is_field() ? "/" : ""); + st->print_cr(" %d <%s.%s%s%s> ", i, klass->as_C_string(), name->as_C_string(), sep, signature->as_C_string()); } @@ -340,12 +369,20 @@ st->print_cr(" " INT32_FORMAT, get_short()); break; case Bytecodes::_ldc: - print_constant(get_index_u1(), st); + if (Bytecodes::uses_cp_cache(raw_code())) { + print_constant(get_index_u1_cpcache(), st); + } else { + print_constant(get_index_u1(), st); + } break; case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: - print_constant(get_index_u2(), st); + if (Bytecodes::uses_cp_cache(raw_code())) { + print_constant(get_index_u2_cpcache(), st); + } else { + print_constant(get_index_u2(), st); + } break; case Bytecodes::_iload: diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/bytecodes.cpp --- a/hotspot/src/share/vm/interpreter/bytecodes.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -489,6 +489,9 @@ def(_return_register_finalizer , "return_register_finalizer" , "b" , NULL , T_VOID , 0, true, _return); + def(_fast_aldc , "fast_aldc" , "bj" , NULL , T_OBJECT, 1, true, _ldc ); + def(_fast_aldc_w , "fast_aldc_w" , "bJJ" , NULL , T_OBJECT, 1, true, _ldc_w ); + def(_shouldnotreachhere , "_shouldnotreachhere" , "b" , NULL , T_VOID , 0, false); // platform specific JVM bytecodes diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/bytecodes.hpp --- a/hotspot/src/share/vm/interpreter/bytecodes.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/bytecodes.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -270,6 +270,10 @@ _fast_linearswitch , _fast_binaryswitch , + // special handling of oop constants: + _fast_aldc , + _fast_aldc_w , + _return_register_finalizer , _shouldnotreachhere, // For debugging diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/interpreter.cpp --- a/hotspot/src/share/vm/interpreter/interpreter.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -99,11 +99,6 @@ #endif // PRODUCT // need to hit every safepoint in order to call zapping routine // register the interpreter - VTune::register_stub( - "Interpreter", - AbstractInterpreter::code()->code_start(), - AbstractInterpreter::code()->code_end() - ); Forte::register_stub( "Interpreter", AbstractInterpreter::code()->code_start(), @@ -267,20 +262,6 @@ } #endif // PRODUCT -static BasicType constant_pool_type(methodOop method, int index) { - constantTag tag = method->constants()->tag_at(index); - if (tag.is_int ()) return T_INT; - else if (tag.is_float ()) return T_FLOAT; - else if (tag.is_long ()) return T_LONG; - else if (tag.is_double ()) return T_DOUBLE; - else if (tag.is_string ()) return T_OBJECT; - else if (tag.is_unresolved_string()) return T_OBJECT; - else if (tag.is_klass ()) return T_OBJECT; - else if (tag.is_unresolved_klass ()) return T_OBJECT; - ShouldNotReachHere(); - return T_ILLEGAL; -} - //------------------------------------------------------------------------------------------------------------------------ // Deoptimization support @@ -330,13 +311,15 @@ } case Bytecodes::_ldc : - type = constant_pool_type( method, *(bcp+1) ); - break; - case Bytecodes::_ldc_w : // fall through case Bytecodes::_ldc2_w: - type = constant_pool_type( method, Bytes::get_Java_u2(bcp+1) ); - break; + { + Thread *thread = Thread::current(); + ResourceMark rm(thread); + methodHandle mh(thread, method); + type = Bytecode_loadconstant_at(mh, bci)->result_type(); + break; + } default: type = Bytecodes::result_type(code); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/interpreterRuntime.cpp --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -83,6 +83,18 @@ } IRT_END +IRT_ENTRY(void, InterpreterRuntime::resolve_ldc(JavaThread* thread, Bytecodes::Code bytecode)) { + assert(bytecode == Bytecodes::_fast_aldc || + bytecode == Bytecodes::_fast_aldc_w, "wrong bc"); + ResourceMark rm(thread); + methodHandle m (thread, method(thread)); + Bytecode_loadconstant* ldc = Bytecode_loadconstant_at(m, bci(thread)); + oop result = ldc->resolve_constant(THREAD); + DEBUG_ONLY(ConstantPoolCacheEntry* cpce = m->constants()->cache()->entry_at(ldc->cache_index())); + assert(result == cpce->f1(), "expected result for assembly code"); +} +IRT_END + //------------------------------------------------------------------------------------------------------------------------ // Allocation @@ -328,7 +340,7 @@ typeArrayHandle h_extable (thread, h_method->exception_table()); bool should_repeat; int handler_bci; - int current_bci = bcp(thread) - h_method->code_base(); + int current_bci = bci(thread); // Need to do this check first since when _do_not_unlock_if_synchronized // is set, we don't want to trigger any classloading which may make calls @@ -615,8 +627,7 @@ if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) { ResourceMark rm(thread); methodHandle m (thread, method(thread)); - int bci = m->bci_from(bcp(thread)); - Bytecode_invoke* call = Bytecode_invoke_at(m, bci); + Bytecode_invoke* call = Bytecode_invoke_at(m, bci(thread)); symbolHandle signature (thread, call->signature()); receiver = Handle(thread, thread->last_frame().interpreter_callee_receiver(signature)); @@ -1257,7 +1268,7 @@ Bytecode_invoke* invoke = Bytecode_invoke_at(mh, bci); ArgumentSizeComputer asc(invoke->signature()); int size_of_arguments = (asc.size() + (invoke->has_receiver() ? 1 : 0)); // receiver - Copy::conjoint_bytes(src_address, dest_address, + Copy::conjoint_jbytes(src_address, dest_address, size_of_arguments * Interpreter::stackElementSize); IRT_END #endif diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/interpreterRuntime.hpp --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -34,6 +34,7 @@ static frame last_frame(JavaThread *thread) { return thread->last_frame(); } static methodOop method(JavaThread *thread) { return last_frame(thread).interpreter_frame_method(); } static address bcp(JavaThread *thread) { return last_frame(thread).interpreter_frame_bcp(); } + static int bci(JavaThread *thread) { return last_frame(thread).interpreter_frame_bci(); } static void set_bcp_and_mdp(address bcp, JavaThread*thread); static Bytecodes::Code code(JavaThread *thread) { // pass method to avoid calling unsafe bcp_to_method (partial fix 4926272) @@ -59,6 +60,7 @@ public: // Constants static void ldc (JavaThread* thread, bool wide); + static void resolve_ldc (JavaThread* thread, Bytecodes::Code bytecode); // Allocation static void _new (JavaThread* thread, constantPoolOopDesc* pool, int index); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/rewriter.cpp --- a/hotspot/src/share/vm/interpreter/rewriter.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -38,6 +38,8 @@ case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_Fieldref : // fall through case JVM_CONSTANT_Methodref : // fall through + case JVM_CONSTANT_MethodHandle : // fall through + case JVM_CONSTANT_MethodType : // fall through add_cp_cache_entry(i); break; } @@ -131,6 +133,27 @@ } +// Rewrite some ldc bytecodes to _fast_aldc +void Rewriter::maybe_rewrite_ldc(address bcp, int offset, bool is_wide) { + assert((*bcp) == (is_wide ? Bytecodes::_ldc_w : Bytecodes::_ldc), ""); + address p = bcp + offset; + int cp_index = is_wide ? Bytes::get_Java_u2(p) : (u1)(*p); + constantTag tag = _pool->tag_at(cp_index).value(); + if (tag.is_method_handle() || tag.is_method_type()) { + int cache_index = cp_entry_to_cp_cache(cp_index); + if (is_wide) { + (*bcp) = Bytecodes::_fast_aldc_w; + assert(cache_index == (u2)cache_index, ""); + Bytes::put_native_u2(p, cache_index); + } else { + (*bcp) = Bytecodes::_fast_aldc; + assert(cache_index == (u1)cache_index, ""); + (*p) = (u1)cache_index; + } + } +} + + // Rewrites a method given the index_map information void Rewriter::scan_method(methodOop method) { @@ -198,6 +221,12 @@ case Bytecodes::_invokedynamic: rewrite_invokedynamic(bcp, prefix_length+1); break; + case Bytecodes::_ldc: + maybe_rewrite_ldc(bcp, prefix_length+1, false); + break; + case Bytecodes::_ldc_w: + maybe_rewrite_ldc(bcp, prefix_length+1, true); + break; case Bytecodes::_jsr : // fall through case Bytecodes::_jsr_w : nof_jsrs++; break; case Bytecodes::_monitorenter : // fall through diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/rewriter.hpp --- a/hotspot/src/share/vm/interpreter/rewriter.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/rewriter.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -66,6 +66,7 @@ void rewrite_Object_init(methodHandle m, TRAPS); void rewrite_member_reference(address bcp, int offset); void rewrite_invokedynamic(address bcp, int offset); + void maybe_rewrite_ldc(address bcp, int offset, bool is_wide); public: // Driver routine: diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/templateTable.cpp --- a/hotspot/src/share/vm/interpreter/templateTable.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/templateTable.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -507,6 +507,9 @@ def(Bytecodes::_fast_linearswitch , ubcp|disp|____|____, itos, vtos, fast_linearswitch , _ ); def(Bytecodes::_fast_binaryswitch , ubcp|disp|____|____, itos, vtos, fast_binaryswitch , _ ); + def(Bytecodes::_fast_aldc , ubcp|____|clvm|____, vtos, atos, fast_aldc , false ); + def(Bytecodes::_fast_aldc_w , ubcp|____|clvm|____, vtos, atos, fast_aldc , true ); + def(Bytecodes::_return_register_finalizer , ____|disp|clvm|____, vtos, vtos, _return , vtos ); def(Bytecodes::_shouldnotreachhere , ____|____|____|____, vtos, vtos, shouldnotreachhere , _ ); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/interpreter/templateTable.hpp --- a/hotspot/src/share/vm/interpreter/templateTable.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/templateTable.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -123,6 +123,7 @@ static void sipush(); static void ldc(bool wide); static void ldc2_w(); + static void fast_aldc(bool wide); static void locals_index(Register reg, int offset = 1); static void iload(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/memory/cardTableModRefBS.cpp --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -284,12 +284,19 @@ committed_unique_to_self(ind, MemRegion(new_end_aligned, cur_committed.end())); if (!uncommit_region.is_empty()) { - if (!os::uncommit_memory((char*)uncommit_region.start(), - uncommit_region.byte_size())) { - assert(false, "Card table contraction failed"); - // The call failed so don't change the end of the - // committed region. This is better than taking the - // VM down. + // It is not safe to uncommit cards if the boundary between + // the generations is moving. A shrink can uncommit cards + // owned by generation A but being used by generation B. + if (!UseAdaptiveGCBoundary) { + if (!os::uncommit_memory((char*)uncommit_region.start(), + uncommit_region.byte_size())) { + assert(false, "Card table contraction failed"); + // The call failed so don't change the end of the + // committed region. This is better than taking the + // VM down. + new_end_aligned = _committed[ind].end(); + } + } else { new_end_aligned = _committed[ind].end(); } } @@ -297,6 +304,19 @@ // In any case, we can reset the end of the current committed entry. _committed[ind].set_end(new_end_aligned); +#ifdef ASSERT + // Check that the last card in the new region is committed according + // to the tables. + bool covered = false; + for (int cr = 0; cr < _cur_covered_regions; cr++) { + if (_committed[cr].contains(new_end - 1)) { + covered = true; + break; + } + } + assert(covered, "Card for end of new region not committed"); +#endif + // The default of 0 is not necessarily clean cards. jbyte* entry; if (old_region.last() < _whole_heap.start()) { @@ -354,6 +374,9 @@ addr_for((jbyte*) _committed[ind].start()), addr_for((jbyte*) _committed[ind].last())); } + // Touch the last card of the covered region to show that it + // is committed (or SEGV). + debug_only(*byte_for(_covered[ind].last());) debug_only(verify_guard();) } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/memory/genCollectedHeap.cpp --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -179,9 +179,14 @@ } n_covered_regions += _gen_specs[i]->n_covered_regions(); } - assert(total_reserved % pageSize == 0, "Gen size"); + assert(total_reserved % pageSize == 0, + err_msg("Gen size; total_reserved=" SIZE_FORMAT ", pageSize=" + SIZE_FORMAT, total_reserved, pageSize)); total_reserved += perm_gen_spec->max_size(); - assert(total_reserved % pageSize == 0, "Perm Gen size"); + assert(total_reserved % pageSize == 0, + err_msg("Perm size; total_reserved=" SIZE_FORMAT ", pageSize=" + SIZE_FORMAT ", perm gen max=" SIZE_FORMAT, total_reserved, + pageSize, perm_gen_spec->max_size())); if (total_reserved < perm_gen_spec->max_size()) { vm_exit_during_initialization(overflow_msg); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/oops/constantPoolKlass.cpp --- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -372,6 +372,13 @@ entry->print_value_on(st); } break; + case JVM_CONSTANT_MethodHandle : + st->print("ref_kind=%d", cp->method_handle_ref_kind_at(index)); + st->print(" ref_index=%d", cp->method_handle_index_at(index)); + break; + case JVM_CONSTANT_MethodType : + st->print("signature_index=%d", cp->method_type_index_at(index)); + break; default: ShouldNotReachHere(); break; @@ -437,6 +444,7 @@ // can be non-perm, can be non-instance (array) } } + // FIXME: verify JSR 292 tags JVM_CONSTANT_MethodHandle, etc. base++; } guarantee(cp->tags()->is_perm(), "should be in permspace"); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/oops/constantPoolOop.cpp --- a/hotspot/src/share/vm/oops/constantPoolOop.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -358,6 +358,11 @@ return klass_at_noresolve(ref_index); } +symbolOop constantPoolOopDesc::uncached_klass_ref_at_noresolve(int which) { + jint ref_index = uncached_klass_ref_index_at(which); + return klass_at_noresolve(ref_index); +} + char* constantPoolOopDesc::string_at_noresolve(int which) { // Test entry type in case string is resolved while in here. oop entry = *(obj_at_addr(which)); @@ -384,6 +389,119 @@ } } +oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) { + oop result_oop = NULL; + if (cache_index >= 0) { + assert(index < 0, "only one kind of index at a time"); + ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index); + result_oop = cpc_entry->f1(); + if (result_oop != NULL) { + return result_oop; // that was easy... + } + index = cpc_entry->constant_pool_index(); + } + + int tag_value = this_oop->tag_at(index).value(); + switch (tag_value) { + + case JVM_CONSTANT_UnresolvedClass: + case JVM_CONSTANT_UnresolvedClassInError: + case JVM_CONSTANT_Class: + { + klassOop resolved = klass_at_impl(this_oop, index, CHECK_NULL); + // ldc wants the java mirror. + result_oop = resolved->klass_part()->java_mirror(); + break; + } + + case JVM_CONSTANT_String: + case JVM_CONSTANT_UnresolvedString: + if (this_oop->is_pseudo_string_at(index)) { + result_oop = this_oop->pseudo_string_at(index); + break; + } + result_oop = string_at_impl(this_oop, index, CHECK_NULL); + break; + + case JVM_CONSTANT_Object: + result_oop = this_oop->object_at(index); + break; + + case JVM_CONSTANT_MethodHandle: + { + int ref_kind = this_oop->method_handle_ref_kind_at(index); + int callee_index = this_oop->method_handle_klass_index_at(index); + symbolHandle name(THREAD, this_oop->method_handle_name_ref_at(index)); + symbolHandle signature(THREAD, this_oop->method_handle_signature_ref_at(index)); + if (PrintMiscellaneous) + tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s", + ref_kind, index, this_oop->method_handle_index_at(index), + callee_index, name->as_C_string(), signature->as_C_string()); + KlassHandle callee; + { klassOop k = klass_at_impl(this_oop, callee_index, CHECK_NULL); + callee = KlassHandle(THREAD, k); + } + KlassHandle klass(THREAD, this_oop->pool_holder()); + Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, + callee, name, signature, + CHECK_NULL); + result_oop = value(); + // FIXME: Uniquify errors, using SystemDictionary::find_resolution_error. + break; + } + + case JVM_CONSTANT_MethodType: + { + symbolHandle signature(THREAD, this_oop->method_type_signature_at(index)); + if (PrintMiscellaneous) + tty->print_cr("resolve JVM_CONSTANT_MethodType [%d/%d] %s", + index, this_oop->method_type_index_at(index), + signature->as_C_string()); + KlassHandle klass(THREAD, this_oop->pool_holder()); + bool ignore_is_on_bcp = false; + Handle value = SystemDictionary::find_method_handle_type(signature, + klass, + ignore_is_on_bcp, + CHECK_NULL); + result_oop = value(); + // FIXME: Uniquify errors, using SystemDictionary::find_resolution_error. + break; + } + + /* maybe some day + case JVM_CONSTANT_Integer: + case JVM_CONSTANT_Float: + case JVM_CONSTANT_Long: + case JVM_CONSTANT_Double: + result_oop = java_lang_boxing_object::create(...); + break; + */ + + default: + DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d", + this_oop(), index, cache_index, tag_value) ); + assert(false, "unexpected constant tag"); + break; + } + + if (cache_index >= 0) { + // Cache the oop here also. + Handle result(THREAD, result_oop); + result_oop = NULL; // safety + ObjectLocker ol(this_oop, THREAD); + ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index); + oop result_oop2 = cpc_entry->f1(); + if (result_oop2 != NULL) { + // Race condition: May already be filled in while we were trying to lock. + return result_oop2; + } + cpc_entry->set_f1(result()); + return result(); + } else { + return result_oop; + } +} + oop constantPoolOopDesc::string_at_impl(constantPoolHandle this_oop, int which, TRAPS) { oop entry = *(this_oop->obj_at_addr(which)); if (entry->is_symbol()) { @@ -690,6 +808,28 @@ } } break; + case JVM_CONSTANT_MethodType: + { + int k1 = method_type_index_at(index1); + int k2 = cp2->method_type_index_at(index2); + if (k1 == k2) { + return true; + } + } break; + + case JVM_CONSTANT_MethodHandle: + { + int k1 = method_handle_ref_kind_at(index1); + int k2 = cp2->method_handle_ref_kind_at(index2); + if (k1 == k2) { + int i1 = method_handle_index_at(index1); + int i2 = cp2->method_handle_index_at(index2); + if (i1 == i2) { + return true; + } + } + } break; + case JVM_CONSTANT_UnresolvedString: { symbolOop s1 = unresolved_string_at(index1); @@ -863,6 +1003,19 @@ to_cp->symbol_at_put(to_i, s); } break; + case JVM_CONSTANT_MethodType: + { + jint k = method_type_index_at(from_i); + to_cp->method_type_index_at_put(to_i, k); + } break; + + case JVM_CONSTANT_MethodHandle: + { + int k1 = method_handle_ref_kind_at(from_i); + int k2 = method_handle_index_at(from_i); + to_cp->method_handle_index_at_put(to_i, k1, k2); + } break; + // Invalid is used as the tag for the second constant pool entry // occupied by JVM_CONSTANT_Double or JVM_CONSTANT_Long. It should // not be seen by itself. @@ -1066,8 +1219,12 @@ case JVM_CONSTANT_UnresolvedClassInError: case JVM_CONSTANT_StringIndex: case JVM_CONSTANT_UnresolvedString: + case JVM_CONSTANT_MethodType: return 3; + case JVM_CONSTANT_MethodHandle: + return 4; //tag, ref_kind, ref_index + case JVM_CONSTANT_Integer: case JVM_CONSTANT_Float: case JVM_CONSTANT_Fieldref: @@ -1271,6 +1428,22 @@ DBG(printf("JVM_CONSTANT_StringIndex: %hd", idx1)); break; } + case JVM_CONSTANT_MethodHandle: { + *bytes = JVM_CONSTANT_MethodHandle; + int kind = method_handle_ref_kind_at(idx); + idx1 = method_handle_index_at(idx); + *(bytes+1) = (unsigned char) kind; + Bytes::put_Java_u2((address) (bytes+2), idx1); + DBG(printf("JVM_CONSTANT_MethodHandle: %d %hd", kind, idx1)); + break; + } + case JVM_CONSTANT_MethodType: { + *bytes = JVM_CONSTANT_MethodType; + idx1 = method_type_index_at(idx); + Bytes::put_Java_u2((address) (bytes+1), idx1); + DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1)); + break; + } } DBG(printf("\n")); bytes += ent_size; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/oops/constantPoolOop.hpp --- a/hotspot/src/share/vm/oops/constantPoolOop.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -146,6 +146,16 @@ oop_store_without_check(obj_at_addr(which), oop(s)); } + void method_handle_index_at_put(int which, int ref_kind, int ref_index) { + tag_at_put(which, JVM_CONSTANT_MethodHandle); + *int_at_addr(which) = ((jint) ref_index<<16) | ref_kind; + } + + void method_type_index_at_put(int which, int ref_index) { + tag_at_put(which, JVM_CONSTANT_MethodType); + *int_at_addr(which) = ref_index; + } + // Temporary until actual use void unresolved_string_at_put(int which, symbolOop s) { *obj_at_addr(which) = NULL; @@ -357,6 +367,36 @@ return *int_at_addr(which); } + int method_handle_ref_kind_at(int which) { + assert(tag_at(which).is_method_handle(), "Corrupted constant pool"); + return extract_low_short_from_int(*int_at_addr(which)); // mask out unwanted ref_index bits + } + int method_handle_index_at(int which) { + assert(tag_at(which).is_method_handle(), "Corrupted constant pool"); + return extract_high_short_from_int(*int_at_addr(which)); // shift out unwanted ref_kind bits + } + int method_type_index_at(int which) { + assert(tag_at(which).is_method_type(), "Corrupted constant pool"); + return *int_at_addr(which); + } + // Derived queries: + symbolOop method_handle_name_ref_at(int which) { + int member = method_handle_index_at(which); + return impl_name_ref_at(member, true); + } + symbolOop method_handle_signature_ref_at(int which) { + int member = method_handle_index_at(which); + return impl_signature_ref_at(member, true); + } + int method_handle_klass_index_at(int which) { + int member = method_handle_index_at(which); + return impl_klass_ref_index_at(member, true); + } + symbolOop method_type_signature_at(int which) { + int sym = method_type_index_at(which); + return symbol_at(sym); + } + // The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve, // name_and_type_ref_index_at) all expect to be passed indices obtained // directly from the bytecode, and extracted according to java byte order. @@ -388,6 +428,17 @@ resolve_string_constants_impl(h_this, CHECK); } + // Resolve late bound constants. + oop resolve_constant_at(int index, TRAPS) { + constantPoolHandle h_this(THREAD, this); + return resolve_constant_at_impl(h_this, index, -1, THREAD); + } + + oop resolve_cached_constant_at(int cache_index, TRAPS) { + constantPoolHandle h_this(THREAD, this); + return resolve_constant_at_impl(h_this, -1, cache_index, THREAD); + } + // Klass name matches name at offset bool klass_name_at_matches(instanceKlassHandle k, int which); @@ -420,6 +471,7 @@ // Routines currently used for annotations (only called by jvm.cpp) but which might be used in the // future by other Java code. These take constant pool indices rather than possibly-byte-swapped // constant pool cache indices as do the peer methods above. + symbolOop uncached_klass_ref_at_noresolve(int which); symbolOop uncached_name_ref_at(int which) { return impl_name_ref_at(which, true); } symbolOop uncached_signature_ref_at(int which) { return impl_signature_ref_at(which, true); } int uncached_klass_ref_index_at(int which) { return impl_klass_ref_index_at(which, true); } @@ -436,6 +488,8 @@ #ifdef ASSERT enum { CPCACHE_INDEX_TAG = 0x10000 }; // helps keep CP cache indices distinct from CP indices +#else + enum { CPCACHE_INDEX_TAG = 0 }; // in product mode, this zero value is a no-op #endif //ASSERT private: @@ -469,6 +523,8 @@ // Resolve string constants (to prevent allocation during compilation) static void resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS); + static oop resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS); + public: // Merging constantPoolOop support: bool compare_entry_to(int index1, constantPoolHandle cp2, int index2, TRAPS); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/oops/cpCacheOop.hpp --- a/hotspot/src/share/vm/oops/cpCacheOop.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -110,6 +110,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { friend class VMStructs; friend class constantPoolCacheKlass; + friend class constantPoolOopDesc; //resolve_constant_at_impl => set_f1 private: volatile intx _indices; // constant pool index & rewrite bytecodes diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/callnode.cpp --- a/hotspot/src/share/vm/opto/callnode.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/callnode.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1524,7 +1524,7 @@ ConnectionGraph *cgr = phase->C->congraph(); PointsToNode::EscapeState es = PointsToNode::GlobalEscape; if (cgr != NULL) - es = cgr->escape_state(obj_node(), phase); + es = cgr->escape_state(obj_node()); if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { // Mark it eliminated to update any counters this->set_eliminated(); @@ -1627,7 +1627,7 @@ ConnectionGraph *cgr = phase->C->congraph(); PointsToNode::EscapeState es = PointsToNode::GlobalEscape; if (cgr != NULL) - es = cgr->escape_state(obj_node(), phase); + es = cgr->escape_state(obj_node()); if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { // Mark it eliminated to update any counters this->set_eliminated(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/cfgnode.cpp --- a/hotspot/src/share/vm/opto/cfgnode.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/cfgnode.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -472,9 +472,7 @@ assert( n->req() == 2 && n->in(1) != NULL, "Only one data input expected" ); // Break dead loop data path. // Eagerly replace phis with top to avoid phis copies generation. - igvn->add_users_to_worklist(n); - igvn->hash_delete(n); // Yank from hash before hacking edges - igvn->subsume_node(n, top); + igvn->replace_node(n, top); if( max != outcnt() ) { progress = true; j = refresh_out_pos(j); @@ -518,18 +516,17 @@ igvn->hash_delete(n); // Remove from worklist before modifying edges if( n->is_Phi() ) { // Collapse all Phis // Eagerly replace phis to avoid copies generation. - igvn->add_users_to_worklist(n); - igvn->hash_delete(n); // Yank from hash before hacking edges + Node* in; if( cnt == 0 ) { assert( n->req() == 1, "No data inputs expected" ); - igvn->subsume_node(n, parent_ctrl); // replaced by top + in = parent_ctrl; // replaced by top } else { assert( n->req() == 2 && n->in(1) != NULL, "Only one data input expected" ); - Node* in1 = n->in(1); // replaced by unique input - if( n->as_Phi()->is_unsafe_data_reference(in1) ) - in1 = phase->C->top(); // replaced by top - igvn->subsume_node(n, in1); + in = n->in(1); // replaced by unique input + if( n->as_Phi()->is_unsafe_data_reference(in) ) + in = phase->C->top(); // replaced by top } + igvn->replace_node(n, in); } else if( n->is_Region() ) { // Update all incoming edges assert( !igvn->eqv(n, this), "Must be removed from DefUse edges"); @@ -2127,7 +2124,7 @@ // if it's not there, there's nothing to do. Node* fallthru = proj_out(0); if (fallthru != NULL) { - phase->is_IterGVN()->subsume_node(fallthru, in(0)); + phase->is_IterGVN()->replace_node(fallthru, in(0)); } return phase->C->top(); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/compile.cpp --- a/hotspot/src/share/vm/opto/compile.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/compile.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -637,34 +637,6 @@ if (failing()) return; NOT_PRODUCT( verify_graph_edges(); ) - // Perform escape analysis - if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) { - TracePhase t2("escapeAnalysis", &_t_escapeAnalysis, true); - // Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction. - PhaseGVN* igvn = initial_gvn(); - Node* oop_null = igvn->zerocon(T_OBJECT); - Node* noop_null = igvn->zerocon(T_NARROWOOP); - - _congraph = new(comp_arena()) ConnectionGraph(this); - bool has_non_escaping_obj = _congraph->compute_escape(); - -#ifndef PRODUCT - if (PrintEscapeAnalysis) { - _congraph->dump(); - } -#endif - // Cleanup. - if (oop_null->outcnt() == 0) - igvn->hash_delete(oop_null); - if (noop_null->outcnt() == 0) - igvn->hash_delete(noop_null); - - if (!has_non_escaping_obj) { - _congraph = NULL; - } - - if (failing()) return; - } // Now optimize Optimize(); if (failing()) return; @@ -1601,6 +1573,20 @@ if (failing()) return; + // Perform escape analysis + if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) { + TracePhase t2("escapeAnalysis", &_t_escapeAnalysis, true); + ConnectionGraph::do_analysis(this, &igvn); + + if (failing()) return; + + igvn.optimize(); + print_method("Iter GVN 3", 2); + + if (failing()) return; + + } + // Loop transforms on the ideal graph. Range Check Elimination, // peeling, unrolling, etc. @@ -2000,6 +1986,17 @@ } } +#ifdef ASSERT + if( n->is_Mem() ) { + Compile* C = Compile::current(); + int alias_idx = C->get_alias_index(n->as_Mem()->adr_type()); + assert( n->in(0) != NULL || alias_idx != Compile::AliasIdxRaw || + // oop will be recorded in oop map if load crosses safepoint + n->is_Load() && (n->as_Load()->bottom_type()->isa_oopptr() || + LoadNode::is_immutable_value(n->in(MemNode::Address))), + "raw memory operations should have control edge"); + } +#endif // Count FPU ops and common calls, implements item (3) switch( nop ) { // Count all float operations that may use FPU diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/compile.hpp --- a/hotspot/src/share/vm/opto/compile.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/compile.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -362,6 +362,7 @@ Node* macro_node(int idx) { return _macro_nodes->at(idx); } Node* predicate_opaque1_node(int idx) { return _predicate_opaqs->at(idx);} ConnectionGraph* congraph() { return _congraph;} + void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;} void add_macro_node(Node * n) { //assert(n->is_macro(), "must be a macro node"); assert(!_macro_nodes->contains(n), " duplicate entry in expand list"); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/doCall.cpp --- a/hotspot/src/share/vm/opto/doCall.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/doCall.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -343,7 +343,8 @@ // being initialized. Uncommon-trap for not-initialized static or // v-calls. Let interface calls happen. ciInstanceKlass* holder_klass = dest_method->holder(); - if (!holder_klass->is_initialized() && + if (!holder_klass->is_being_initialized() && + !holder_klass->is_initialized() && !holder_klass->is_interface()) { uncommon_trap(Deoptimization::Reason_uninitialized, Deoptimization::Action_reinterpret, diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/escape.cpp --- a/hotspot/src/share/vm/opto/escape.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/escape.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -81,18 +81,18 @@ } #endif -ConnectionGraph::ConnectionGraph(Compile * C) : +ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) : _nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()), _processed(C->comp_arena()), _collecting(true), _compile(C), + _igvn(igvn), _node_map(C->comp_arena()) { _phantom_object = C->top()->_idx, add_node(C->top(), PointsToNode::JavaObject, PointsToNode::GlobalEscape,true); // Add ConP(#NULL) and ConN(#NULL) nodes. - PhaseGVN* igvn = C->initial_gvn(); Node* oop_null = igvn->zerocon(T_OBJECT); _oop_null = oop_null->_idx; assert(_oop_null < C->unique(), "should be created already"); @@ -182,7 +182,7 @@ _processed.set(n->_idx); } -PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n, PhaseTransform *phase) { +PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n) { uint idx = n->_idx; PointsToNode::EscapeState es; @@ -207,22 +207,26 @@ if (n->uncast()->_idx >= nodes_size()) return PointsToNode::UnknownEscape; + PointsToNode::EscapeState orig_es = es; + // compute max escape state of anything this node could point to VectorSet ptset(Thread::current()->resource_area()); - PointsTo(ptset, n, phase); + PointsTo(ptset, n); for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) { uint pt = i.elem; PointsToNode::EscapeState pes = ptnode_adr(pt)->escape_state(); if (pes > es) es = pes; } - // cache the computed escape state - assert(es != PointsToNode::UnknownEscape, "should have computed an escape state"); - ptnode_adr(idx)->set_escape_state(es); + if (orig_es != es) { + // cache the computed escape state + assert(es != PointsToNode::UnknownEscape, "should have computed an escape state"); + ptnode_adr(idx)->set_escape_state(es); + } // orig_es could be PointsToNode::UnknownEscape return es; } -void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase) { +void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n) { VectorSet visited(Thread::current()->resource_area()); GrowableArray worklist; @@ -990,7 +994,7 @@ GrowableArray memnode_worklist; GrowableArray orig_phis; - PhaseGVN *igvn = _compile->initial_gvn(); + PhaseGVN *igvn = _igvn; uint new_index_start = (uint) _compile->num_alias_types(); Arena* arena = Thread::current()->resource_area(); VectorSet visited(arena); @@ -1012,7 +1016,7 @@ CallNode *alloc = n->as_Call(); // copy escape information to call node PointsToNode* ptn = ptnode_adr(alloc->_idx); - PointsToNode::EscapeState es = escape_state(alloc, igvn); + PointsToNode::EscapeState es = escape_state(alloc); // We have an allocation or call which returns a Java object, // see if it is unescaped. if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable) @@ -1123,7 +1127,7 @@ } } else if (n->is_AddP()) { ptset.Clear(); - PointsTo(ptset, get_addp_base(n), igvn); + PointsTo(ptset, get_addp_base(n)); assert(ptset.Size() == 1, "AddP address is unique"); uint elem = ptset.getelem(); // Allocation node's index if (elem == _phantom_object) { @@ -1143,7 +1147,7 @@ continue; // already processed } ptset.Clear(); - PointsTo(ptset, n, igvn); + PointsTo(ptset, n); if (ptset.Size() == 1) { uint elem = ptset.getelem(); // Allocation node's index if (elem == _phantom_object) { @@ -1478,6 +1482,26 @@ return false; } +void ConnectionGraph::do_analysis(Compile *C, PhaseIterGVN *igvn) { + // Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction + // to create space for them in ConnectionGraph::_nodes[]. + Node* oop_null = igvn->zerocon(T_OBJECT); + Node* noop_null = igvn->zerocon(T_NARROWOOP); + + ConnectionGraph* congraph = new(C->comp_arena()) ConnectionGraph(C, igvn); + // Perform escape analysis + if (congraph->compute_escape()) { + // There are non escaping objects. + C->set_congraph(congraph); + } + + // Cleanup. + if (oop_null->outcnt() == 0) + igvn->hash_delete(oop_null); + if (noop_null->outcnt() == 0) + igvn->hash_delete(noop_null); +} + bool ConnectionGraph::compute_escape() { Compile* C = _compile; @@ -1492,7 +1516,7 @@ } GrowableArray cg_worklist; - PhaseGVN* igvn = C->initial_gvn(); + PhaseGVN* igvn = _igvn; bool has_allocations = false; // Push all useful nodes onto CG list and set their type. @@ -1661,6 +1685,12 @@ _collecting = false; assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build"); +#ifndef PRODUCT + if (PrintEscapeAnalysis) { + dump(); // Dump ConnectionGraph + } +#endif + bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0; if ( has_scalar_replaceable_candidates && C->AliasLevel() >= 3 && EliminateAllocations ) { @@ -1671,10 +1701,6 @@ if (C->failing()) return false; - // Clean up after split unique types. - ResourceMark rm; - PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn()); - C->print_method("After Escape Analysis", 2); #ifdef ASSERT @@ -1711,7 +1737,7 @@ int offset = ptn->offset(); Node* base = get_addp_base(n); ptset.Clear(); - PointsTo(ptset, base, phase); + PointsTo(ptset, base); int ptset_size = ptset.Size(); // Check if a oop field's initializing value is recorded and add @@ -1889,7 +1915,7 @@ arg = get_addp_base(arg); } ptset.Clear(); - PointsTo(ptset, arg, phase); + PointsTo(ptset, arg); for( VectorSetI j(&ptset); j.test(); ++j ) { uint pt = j.elem; set_escape_state(pt, PointsToNode::ArgEscape); @@ -1934,7 +1960,7 @@ } ptset.Clear(); - PointsTo(ptset, arg, phase); + PointsTo(ptset, arg); for( VectorSetI j(&ptset); j.test(); ++j ) { uint pt = j.elem; if (global_escapes) { @@ -1970,7 +1996,7 @@ Node *arg = call->in(i)->uncast(); set_escape_state(arg->_idx, PointsToNode::GlobalEscape); ptset.Clear(); - PointsTo(ptset, arg, phase); + PointsTo(ptset, arg); for( VectorSetI j(&ptset); j.test(); ++j ) { uint pt = j.elem; set_escape_state(pt, PointsToNode::GlobalEscape); @@ -2433,7 +2459,7 @@ Node *base = get_addp_base(n); // Create a field edge to this node from everything base could point to. VectorSet ptset(Thread::current()->resource_area()); - PointsTo(ptset, base, phase); + PointsTo(ptset, base); for( VectorSetI i(&ptset); i.test(); ++i ) { uint pt = i.elem; add_field_edge(pt, n_idx, address_offset(n, phase)); @@ -2501,7 +2527,7 @@ // For everything "adr_base" could point to, create a deferred edge from // this node to each field with the same offset. VectorSet ptset(Thread::current()->resource_area()); - PointsTo(ptset, adr_base, phase); + PointsTo(ptset, adr_base); int offset = address_offset(adr, phase); for( VectorSetI i(&ptset); i.test(); ++i ) { uint pt = i.elem; @@ -2594,7 +2620,7 @@ // For everything "adr_base" could point to, create a deferred edge // to "val" from each field with the same offset. VectorSet ptset(Thread::current()->resource_area()); - PointsTo(ptset, adr_base, phase); + PointsTo(ptset, adr_base); for( VectorSetI i(&ptset); i.test(); ++i ) { uint pt = i.elem; add_edge_from_fields(pt, val->_idx, address_offset(adr, phase)); @@ -2638,7 +2664,6 @@ #ifndef PRODUCT void ConnectionGraph::dump() { - PhaseGVN *igvn = _compile->initial_gvn(); bool first = true; uint size = nodes_size(); @@ -2648,7 +2673,7 @@ if (ptn_type != PointsToNode::JavaObject || ptn->_node == NULL) continue; - PointsToNode::EscapeState es = escape_state(ptn->_node, igvn); + PointsToNode::EscapeState es = escape_state(ptn->_node); if (ptn->_node->is_Allocate() && (es == PointsToNode::NoEscape || Verbose)) { if (first) { tty->cr(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/escape.hpp --- a/hotspot/src/share/vm/opto/escape.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/escape.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -227,6 +227,7 @@ uint _noop_null; // ConN(#NULL) Compile * _compile; // Compile object for current compilation + PhaseIterGVN * _igvn; // Value numbering // Address of an element in _nodes. Used when the element is to be modified PointsToNode *ptnode_adr(uint idx) const { @@ -257,7 +258,7 @@ // walk the connection graph starting at the node corresponding to "n" and // add the index of everything it could point to, to "ptset". This may cause // Phi's encountered to get (re)processed (which requires "phase".) - void PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase); + void PointsTo(VectorSet &ptset, Node * n); // Edge manipulation. The "from_i" and "to_i" arguments are the // node indices of the source and destination of the edge @@ -310,7 +311,7 @@ // Node: This assumes that escape analysis is run before // PhaseIterGVN creation void record_for_optimizer(Node *n) { - _compile->record_for_igvn(n); + _igvn->_worklist.push(n); } // Set the escape state of a node @@ -320,16 +321,20 @@ void verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase); public: - ConnectionGraph(Compile *C); + ConnectionGraph(Compile *C, PhaseIterGVN *igvn); // Check for non-escaping candidates static bool has_candidates(Compile *C); + // Perform escape analysis + static void do_analysis(Compile *C, PhaseIterGVN *igvn); + // Compute the escape information bool compute_escape(); // escape state of a node - PointsToNode::EscapeState escape_state(Node *n, PhaseTransform *phase); + PointsToNode::EscapeState escape_state(Node *n); + // other information we have collected bool is_scalar_replaceable(Node *n) { if (_collecting || (n->_idx >= nodes_size())) diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1789,9 +1789,10 @@ void GraphKit::increment_counter(Node* counter_addr) { int adr_type = Compile::AliasIdxRaw; - Node* cnt = make_load(NULL, counter_addr, TypeInt::INT, T_INT, adr_type); + Node* ctrl = control(); + Node* cnt = make_load(ctrl, counter_addr, TypeInt::INT, T_INT, adr_type); Node* incr = _gvn.transform(new (C, 3) AddINode(cnt, _gvn.intcon(1))); - store_to_memory( NULL, counter_addr, incr, T_INT, adr_type ); + store_to_memory( ctrl, counter_addr, incr, T_INT, adr_type ); } @@ -2771,11 +2772,7 @@ // Update the counter for this lock. Don't bother using an atomic // operation since we don't require absolute accuracy. lock->create_lock_counter(map()->jvms()); - int adr_type = Compile::AliasIdxRaw; - Node* counter_addr = makecon(TypeRawPtr::make(lock->counter()->addr())); - Node* cnt = make_load(NULL, counter_addr, TypeInt::INT, T_INT, adr_type); - Node* incr = _gvn.transform(new (C, 3) AddINode(cnt, _gvn.intcon(1))); - store_to_memory(control(), counter_addr, incr, T_INT, adr_type); + increment_counter(lock->counter()->addr()); } #endif diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/ifnode.cpp --- a/hotspot/src/share/vm/opto/ifnode.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/ifnode.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1081,11 +1081,9 @@ igvn->register_new_node_with_optimizer(new_if_f); igvn->register_new_node_with_optimizer(new_if_t); - igvn->hash_delete(old_if_f); - igvn->hash_delete(old_if_t); // Flip test, so flip trailing control - igvn->subsume_node(old_if_f, new_if_t); - igvn->subsume_node(old_if_t, new_if_f); + igvn->replace_node(old_if_f, new_if_t); + igvn->replace_node(old_if_t, new_if_f); // Progress return iff; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -3512,8 +3512,7 @@ // Get the header out of the object, use LoadMarkNode when available Node* header_addr = basic_plus_adr(obj, oopDesc::mark_offset_in_bytes()); - Node* header = make_load(NULL, header_addr, TypeRawPtr::BOTTOM, T_ADDRESS); - header = _gvn.transform( new (C, 2) CastP2XNode(NULL, header) ); + Node* header = make_load(control(), header_addr, TypeX_X, TypeX_X->basic_type()); // Test the header to see if it is unlocked. Node *lock_mask = _gvn.MakeConX(markOopDesc::biased_lock_mask_in_place); @@ -5202,7 +5201,7 @@ // super_check_offset, for the desired klass. int sco_offset = Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc); Node* p3 = basic_plus_adr(dest_elem_klass, sco_offset); - Node* n3 = new(C, 3) LoadINode(NULL, immutable_memory(), p3, TypeRawPtr::BOTTOM); + Node* n3 = new(C, 3) LoadINode(NULL, memory(p3), p3, _gvn.type(p3)->is_ptr()); Node* check_offset = _gvn.transform(n3); Node* check_value = dest_elem_klass; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -194,8 +194,7 @@ addx = new (phase->C, 3) AddINode(x, inv); } phase->register_new_node(addx, phase->get_ctrl(x)); - phase->_igvn.hash_delete(n1); - phase->_igvn.subsume_node(n1, addx); + phase->_igvn.replace_node(n1, addx); return addx; } @@ -1586,8 +1585,7 @@ Node *phi = cl->phi(); Node *final = new (phase->C, 3) SubINode( cl->limit(), cl->stride() ); phase->register_new_node(final,cl->in(LoopNode::EntryControl)); - phase->_igvn.hash_delete(phi); - phase->_igvn.subsume_node(phi,final); + phase->_igvn.replace_node(phi,final); phase->C->set_major_progress(); return true; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/loopnode.cpp --- a/hotspot/src/share/vm/opto/loopnode.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/loopnode.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -400,7 +400,7 @@ nphi->set_req(LoopNode::LoopBackControl, phi->in(LoopNode::LoopBackControl)); nphi = _igvn.register_new_node_with_optimizer(nphi); set_ctrl(nphi, get_ctrl(phi)); - _igvn.subsume_node(phi, nphi); + _igvn.replace_node(phi, nphi); phi = nphi->as_Phi(); } cmp = cmp->clone(); @@ -760,7 +760,7 @@ // which in turn prevents removing an empty loop. Node *id_old_phi = old_phi->Identity( &igvn ); if( id_old_phi != old_phi ) { // Found a simple identity? - // Note that I cannot call 'subsume_node' here, because + // Note that I cannot call 'replace_node' here, because // that will yank the edge from old_phi to the Region and // I'm mid-iteration over the Region's uses. for (DUIterator_Last imin, i = old_phi->last_outs(imin); i >= imin; ) { @@ -1065,11 +1065,9 @@ l = igvn.register_new_node_with_optimizer(l, _head); phase->set_created_loop_node(); // Go ahead and replace _head - phase->_igvn.subsume_node( _head, l ); + phase->_igvn.replace_node( _head, l ); _head = l; phase->set_loop(_head, this); - for (DUIterator_Fast imax, i = l->fast_outs(imax); i < imax; i++) - phase->_igvn.add_users_to_worklist(l->fast_out(i)); } // Now recursively beautify nested loops @@ -1329,8 +1327,7 @@ Node* add = new (C, 3) AddINode(ratio_idx, diff); phase->_igvn.register_new_node_with_optimizer(add); phase->set_ctrl(add, cl); - phase->_igvn.hash_delete( phi2 ); - phase->_igvn.subsume_node( phi2, add ); + phase->_igvn.replace_node( phi2, add ); // Sometimes an induction variable is unused if (add->outcnt() == 0) { phase->_igvn.remove_dead_node(add); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/loopnode.hpp --- a/hotspot/src/share/vm/opto/loopnode.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/loopnode.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -626,8 +626,7 @@ _nodes.map( old_node->_idx, (Node*)((intptr_t)new_node + 1) ); } void lazy_replace( Node *old_node, Node *new_node ) { - _igvn.hash_delete(old_node); - _igvn.subsume_node( old_node, new_node ); + _igvn.replace_node( old_node, new_node ); lazy_update( old_node, new_node ); } void lazy_replace_proj( Node *old_node, Node *new_node ) { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/loopopts.cpp --- a/hotspot/src/share/vm/opto/loopopts.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/loopopts.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -354,8 +354,7 @@ register_new_node( var_scale, n_ctrl ); Node *var_add = new (C, 3) AddINode( var_scale, inv_scale ); register_new_node( var_add, n_ctrl ); - _igvn.hash_delete( n ); - _igvn.subsume_node( n, var_add ); + _igvn.replace_node( n, var_add ); return var_add; } @@ -390,8 +389,7 @@ register_new_node( add1, n_loop->_head->in(LoopNode::EntryControl) ); Node *add2 = new (C, 4) AddPNode( n->in(1), add1, n->in(2)->in(3) ); register_new_node( add2, n_ctrl ); - _igvn.hash_delete( n ); - _igvn.subsume_node( n, add2 ); + _igvn.replace_node( n, add2 ); return add2; } } @@ -412,8 +410,7 @@ register_new_node( add1, n_loop->_head->in(LoopNode::EntryControl) ); Node *add2 = new (C, 4) AddPNode( n->in(1), add1, V ); register_new_node( add2, n_ctrl ); - _igvn.hash_delete( n ); - _igvn.subsume_node( n, add2 ); + _igvn.replace_node( n, add2 ); return add2; } } @@ -555,8 +552,7 @@ } Node *cmov = CMoveNode::make( C, cmov_ctrl, iff->in(1), phi->in(1+flip), phi->in(2-flip), _igvn.type(phi) ); register_new_node( cmov, cmov_ctrl ); - _igvn.hash_delete(phi); - _igvn.subsume_node( phi, cmov ); + _igvn.replace_node( phi, cmov ); #ifndef PRODUCT if( VerifyLoopOptimizations ) verify(); #endif @@ -642,8 +638,7 @@ // Found a Phi to split thru! // Replace 'n' with the new phi - _igvn.hash_delete(n); - _igvn.subsume_node( n, phi ); + _igvn.replace_node( n, phi ); // Moved a load around the loop, 'en-registering' something. if( n_blk->Opcode() == Op_Loop && n->is_Load() && !phi->in(LoopNode::LoopBackControl)->is_Load() ) @@ -789,13 +784,11 @@ // Found a Phi to split thru! // Replace 'n' with the new phi - _igvn.hash_delete(n); - _igvn.subsume_node( n, phi ); + _igvn.replace_node( n, phi ); // Now split the bool up thru the phi Node *bolphi = split_thru_phi( bol, n_ctrl, -1 ); - _igvn.hash_delete(bol); - _igvn.subsume_node( bol, bolphi ); + _igvn.replace_node( bol, bolphi ); assert( iff->in(1) == bolphi, "" ); if( bolphi->Value(&_igvn)->singleton() ) return; @@ -803,8 +796,7 @@ // Conditional-move? Must split up now if( !iff->is_If() ) { Node *cmovphi = split_thru_phi( iff, n_ctrl, -1 ); - _igvn.hash_delete(iff); - _igvn.subsume_node( iff, cmovphi ); + _igvn.replace_node( iff, cmovphi ); return; } @@ -950,9 +942,7 @@ if( n_op == Op_Opaque2 && n->in(1) != NULL && get_loop(get_ctrl(n)) == get_loop(get_ctrl(n->in(1))) ) { - _igvn.add_users_to_worklist(n); - _igvn.hash_delete(n); - _igvn.subsume_node( n, n->in(1) ); + _igvn.replace_node( n, n->in(1) ); } } @@ -1425,7 +1415,7 @@ // IGVN does CSE). Node *hit = _igvn.hash_find_insert(use); if( hit ) // Go ahead and re-hash for hits. - _igvn.subsume_node( use, hit ); + _igvn.replace_node( use, hit ); } // If 'use' was in the loop-exit block, it now needs to be sunk diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/macro.cpp --- a/hotspot/src/share/vm/opto/macro.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/macro.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -135,8 +135,7 @@ if (parm1 != NULL) call->init_req(TypeFunc::Parms+1, parm1); copy_call_debug_info(oldcall, call); call->set_cnt(PROB_UNLIKELY_MAG(4)); // Same effect as RC_UNCOMMON. - _igvn.hash_delete(oldcall); - _igvn.subsume_node(oldcall, call); + _igvn.replace_node(oldcall, call); transform_later(call); return call; @@ -523,8 +522,7 @@ // Kill all new Phis while(value_phis.is_nonempty()) { Node* n = value_phis.node(); - _igvn.hash_delete(n); - _igvn.subsume_node(n, C->top()); + _igvn.replace_node(n, C->top()); value_phis.pop(); } } @@ -1311,8 +1309,7 @@ if (!always_slow) { call->set_cnt(PROB_UNLIKELY_MAG(4)); // Same effect as RC_UNCOMMON. } - _igvn.hash_delete(alloc); - _igvn.subsume_node(alloc, call); + _igvn.replace_node(alloc, call); transform_later(call); // Identify the output projections from the allocate node and @@ -1431,7 +1428,7 @@ Node* mark_node = NULL; // For now only enable fast locking for non-array types if (UseBiasedLocking && (length == NULL)) { - mark_node = make_load(NULL, rawmem, klass_node, Klass::prototype_header_offset_in_bytes() + sizeof(oopDesc), TypeRawPtr::BOTTOM, T_ADDRESS); + mark_node = make_load(control, rawmem, klass_node, Klass::prototype_header_offset_in_bytes() + sizeof(oopDesc), TypeRawPtr::BOTTOM, T_ADDRESS); } else { mark_node = makecon(TypeRawPtr::make((address)markOopDesc::prototype())); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/memnode.cpp --- a/hotspot/src/share/vm/opto/memnode.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/memnode.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -815,6 +815,16 @@ } #endif +#ifdef ASSERT +//----------------------------is_immutable_value------------------------------- +// Helper function to allow a raw load without control edge for some cases +bool LoadNode::is_immutable_value(Node* adr) { + return (adr->is_AddP() && adr->in(AddPNode::Base)->is_top() && + adr->in(AddPNode::Address)->Opcode() == Op_ThreadLocal && + (adr->in(AddPNode::Offset)->find_intptr_t_con(-1) == + in_bytes(JavaThread::osthread_offset()))); +} +#endif //----------------------------LoadNode::make----------------------------------- // Polymorphic factory method: @@ -828,6 +838,11 @@ assert(!(adr_type->isa_aryptr() && adr_type->offset() == arrayOopDesc::length_offset_in_bytes()), "use LoadRangeNode instead"); + // Check control edge of raw loads + assert( ctl != NULL || C->get_alias_index(adr_type) != Compile::AliasIdxRaw || + // oop will be recorded in oop map if load crosses safepoint + rt->isa_oopptr() || is_immutable_value(adr), + "raw memory operations should have control edge"); switch (bt) { case T_BOOLEAN: return new (C, 3) LoadUBNode(ctl, mem, adr, adr_type, rt->is_int() ); case T_BYTE: return new (C, 3) LoadBNode (ctl, mem, adr, adr_type, rt->is_int() ); @@ -2064,6 +2079,8 @@ // Polymorphic factory method: StoreNode* StoreNode::make( PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, BasicType bt ) { Compile* C = gvn.C; + assert( C->get_alias_index(adr_type) != Compile::AliasIdxRaw || + ctl != NULL, "raw memory operations should have control edge"); switch (bt) { case T_BOOLEAN: diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/memnode.hpp --- a/hotspot/src/share/vm/opto/memnode.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/memnode.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -189,6 +189,10 @@ #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif +#ifdef ASSERT + // Helper function to allow a raw load without control edge for some cases + static bool is_immutable_value(Node* adr); +#endif protected: const Type* load_array_final_field(const TypeKlassPtr *tkls, ciKlass* klass) const; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/parse.hpp --- a/hotspot/src/share/vm/opto/parse.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/parse.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -480,6 +480,7 @@ bool push_constant(ciConstant con, bool require_constant = false); // implementation of object creation bytecodes + void emit_guard_for_new(ciInstanceKlass* klass); void do_new(); void do_newarray(BasicType elemtype); void do_anewarray(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/parse1.cpp --- a/hotspot/src/share/vm/opto/parse1.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/parse1.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -88,15 +88,16 @@ Node *local_addrs_base) { Node *mem = memory(Compile::AliasIdxRaw); Node *adr = basic_plus_adr( local_addrs_base, local_addrs, -index*wordSize ); + Node *ctl = control(); // Very similar to LoadNode::make, except we handle un-aligned longs and // doubles on Sparc. Intel can handle them just fine directly. Node *l; switch( bt ) { // Signature is flattened - case T_INT: l = new (C, 3) LoadINode( 0, mem, adr, TypeRawPtr::BOTTOM ); break; - case T_FLOAT: l = new (C, 3) LoadFNode( 0, mem, adr, TypeRawPtr::BOTTOM ); break; - case T_ADDRESS: l = new (C, 3) LoadPNode( 0, mem, adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM ); break; - case T_OBJECT: l = new (C, 3) LoadPNode( 0, mem, adr, TypeRawPtr::BOTTOM, TypeInstPtr::BOTTOM ); break; + case T_INT: l = new (C, 3) LoadINode( ctl, mem, adr, TypeRawPtr::BOTTOM ); break; + case T_FLOAT: l = new (C, 3) LoadFNode( ctl, mem, adr, TypeRawPtr::BOTTOM ); break; + case T_ADDRESS: l = new (C, 3) LoadPNode( ctl, mem, adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM ); break; + case T_OBJECT: l = new (C, 3) LoadPNode( ctl, mem, adr, TypeRawPtr::BOTTOM, TypeInstPtr::BOTTOM ); break; case T_LONG: case T_DOUBLE: { // Since arguments are in reverse order, the argument address 'adr' @@ -104,12 +105,12 @@ adr = basic_plus_adr( local_addrs_base, local_addrs, -(index+1)*wordSize ); if( Matcher::misaligned_doubles_ok ) { l = (bt == T_DOUBLE) - ? (Node*)new (C, 3) LoadDNode( 0, mem, adr, TypeRawPtr::BOTTOM ) - : (Node*)new (C, 3) LoadLNode( 0, mem, adr, TypeRawPtr::BOTTOM ); + ? (Node*)new (C, 3) LoadDNode( ctl, mem, adr, TypeRawPtr::BOTTOM ) + : (Node*)new (C, 3) LoadLNode( ctl, mem, adr, TypeRawPtr::BOTTOM ); } else { l = (bt == T_DOUBLE) - ? (Node*)new (C, 3) LoadD_unalignedNode( 0, mem, adr, TypeRawPtr::BOTTOM ) - : (Node*)new (C, 3) LoadL_unalignedNode( 0, mem, adr, TypeRawPtr::BOTTOM ); + ? (Node*)new (C, 3) LoadD_unalignedNode( ctl, mem, adr, TypeRawPtr::BOTTOM ) + : (Node*)new (C, 3) LoadL_unalignedNode( ctl, mem, adr, TypeRawPtr::BOTTOM ); } break; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/parse2.cpp --- a/hotspot/src/share/vm/opto/parse2.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/parse2.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1324,33 +1324,21 @@ case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: // If the constant is unresolved, run this BC once in the interpreter. - if (iter().is_unresolved_string()) { - uncommon_trap(Deoptimization::make_trap_request - (Deoptimization::Reason_unloaded, - Deoptimization::Action_reinterpret, - iter().get_constant_index()), - NULL, "unresolved_string"); - break; - } else { + { ciConstant constant = iter().get_constant(); - if (constant.basic_type() == T_OBJECT) { - ciObject* c = constant.as_object(); - if (c->is_klass()) { - // The constant returned for a klass is the ciKlass for the - // entry. We want the java_mirror so get it. - ciKlass* klass = c->as_klass(); - if (klass->is_loaded()) { - constant = ciConstant(T_OBJECT, klass->java_mirror()); - } else { - uncommon_trap(Deoptimization::make_trap_request - (Deoptimization::Reason_unloaded, - Deoptimization::Action_reinterpret, - iter().get_constant_index()), - NULL, "unresolved_klass"); - break; - } - } + if (constant.basic_type() == T_OBJECT && + !constant.as_object()->is_loaded()) { + int index = iter().get_constant_pool_index(); + constantTag tag = iter().get_constant_pool_tag(index); + uncommon_trap(Deoptimization::make_trap_request + (Deoptimization::Reason_unloaded, + Deoptimization::Action_reinterpret, + index), + NULL, tag.internal_name()); + break; } + assert(constant.basic_type() != T_OBJECT || !constant.as_object()->is_klass(), + "must be java_mirror of klass"); bool pushed = push_constant(constant, true); guarantee(pushed, "must be possible to push this constant"); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/parseHelper.cpp --- a/hotspot/src/share/vm/opto/parseHelper.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/parseHelper.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -197,6 +197,43 @@ } +void Parse::emit_guard_for_new(ciInstanceKlass* klass) { + // Emit guarded new + // if (klass->_init_thread != current_thread || + // klass->_init_state != being_initialized) + // uncommon_trap + Node* cur_thread = _gvn.transform( new (C, 1) ThreadLocalNode() ); + Node* merge = new (C, 3) RegionNode(3); + _gvn.set_type(merge, Type::CONTROL); + Node* kls = makecon(TypeKlassPtr::make(klass)); + + Node* init_thread_offset = _gvn.MakeConX(instanceKlass::init_thread_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()); + Node* adr_node = basic_plus_adr(kls, kls, init_thread_offset); + Node* init_thread = make_load(NULL, adr_node, TypeRawPtr::BOTTOM, T_ADDRESS); + Node *tst = Bool( CmpP( init_thread, cur_thread), BoolTest::eq); + IfNode* iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN); + set_control(IfTrue(iff)); + merge->set_req(1, IfFalse(iff)); + + Node* init_state_offset = _gvn.MakeConX(instanceKlass::init_state_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()); + adr_node = basic_plus_adr(kls, kls, init_state_offset); + Node* init_state = make_load(NULL, adr_node, TypeInt::INT, T_INT); + Node* being_init = _gvn.intcon(instanceKlass::being_initialized); + tst = Bool( CmpI( init_state, being_init), BoolTest::eq); + iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN); + set_control(IfTrue(iff)); + merge->set_req(2, IfFalse(iff)); + + PreserveJVMState pjvms(this); + record_for_igvn(merge); + set_control(merge); + + uncommon_trap(Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret, + klass); +} + + //------------------------------do_new----------------------------------------- void Parse::do_new() { kill_dead_locals(); @@ -206,7 +243,7 @@ assert(will_link, "_new: typeflow responsibility"); // Should initialize, or throw an InstantiationError? - if (!klass->is_initialized() || + if (!klass->is_initialized() && !klass->is_being_initialized() || klass->is_abstract() || klass->is_interface() || klass->name() == ciSymbol::java_lang_Class() || iter().is_unresolved_klass()) { @@ -215,6 +252,9 @@ klass); return; } + if (klass->is_being_initialized()) { + emit_guard_for_new(klass); + } Node* kls = makecon(TypeKlassPtr::make(klass)); Node* obj = new_instance(kls); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/phaseX.cpp --- a/hotspot/src/share/vm/opto/phaseX.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/phaseX.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1447,16 +1447,12 @@ Node* m = n->out(i); if( m->is_Phi() ) { assert(type(m) == Type::TOP, "Unreachable region should not have live phis."); - add_users_to_worklist(m); - hash_delete(m); // Yank from hash before hacking edges - subsume_node(m, nn); + replace_node(m, nn); --i; // deleted this phi; rescan starting with next position } } } - add_users_to_worklist(n); // Users of about-to-be-constant 'n' - hash_delete(n); // Removed 'n' from table before subsuming it - subsume_node(n,nn); // Update DefUse edges for new constant + replace_node(n,nn); // Update DefUse edges for new constant } return nn; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/phaseX.hpp --- a/hotspot/src/share/vm/opto/phaseX.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/phaseX.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -393,6 +393,10 @@ // Idealize old Node 'n' with respect to its inputs and its value virtual Node *transform_old( Node *a_node ); + + // Subsume users of node 'old' into node 'nn' + void subsume_node( Node *old, Node *nn ); + protected: // Idealize new Node 'n' with respect to its inputs and its value @@ -439,10 +443,6 @@ remove_globally_dead_node(dead); } - // Subsume users of node 'old' into node 'nn' - // If no Def-Use info existed for 'nn' it will after call. - void subsume_node( Node *old, Node *nn ); - // Add users of 'n' to worklist void add_users_to_worklist0( Node *n ); void add_users_to_worklist ( Node *n ); @@ -450,7 +450,7 @@ // Replace old node with new one. void replace_node( Node *old, Node *nn ) { add_users_to_worklist(old); - hash_delete(old); + hash_delete(old); // Yank from hash before hacking edges subsume_node(old, nn); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/split_if.cpp --- a/hotspot/src/share/vm/opto/split_if.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/split_if.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -217,8 +217,7 @@ register_new_node(phi, blk1); // Remove cloned-up value from optimizer; use phi instead - _igvn.hash_delete(n); - _igvn.subsume_node( n, phi ); + _igvn.replace_node( n, phi ); // (There used to be a self-recursive call to split_up() here, // but it is not needed. All necessary forward walking is done @@ -352,8 +351,7 @@ } if (use_blk == NULL) { // He's dead, Jim - _igvn.hash_delete(use); - _igvn.subsume_node(use, C->top()); + _igvn.replace_node(use, C->top()); } return use_blk; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/superword.cpp --- a/hotspot/src/share/vm/opto/superword.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/superword.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1172,8 +1172,7 @@ _phase->set_ctrl(vn, _phase->get_ctrl(p->at(0))); for (uint j = 0; j < p->size(); j++) { Node* pm = p->at(j); - _igvn.hash_delete(pm); - _igvn.subsume_node(pm, vn); + _igvn.replace_node(pm, vn); } _igvn._worklist.push(vn); } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/opto/type.cpp --- a/hotspot/src/share/vm/opto/type.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/opto/type.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -182,6 +182,8 @@ return t->hash(); } +#define SMALLINT ((juint)3) // a value too insignificant to consider widening + //--------------------------Initialize_shared---------------------------------- void Type::Initialize_shared(Compile* current) { // This method does not need to be locked because the first system @@ -240,6 +242,7 @@ assert( TypeInt::CC_GT == TypeInt::ONE, "types must match for CmpL to work" ); assert( TypeInt::CC_EQ == TypeInt::ZERO, "types must match for CmpL to work" ); assert( TypeInt::CC_GE == TypeInt::BOOL, "types must match for CmpL to work" ); + assert( (juint)(TypeInt::CC->_hi - TypeInt::CC->_lo) <= SMALLINT, "CC is truly small"); TypeLong::MINUS_1 = TypeLong::make(-1); // -1 TypeLong::ZERO = TypeLong::make( 0); // 0 @@ -1054,16 +1057,21 @@ return (TypeInt*)(new TypeInt(lo,lo,WidenMin))->hashcons(); } -#define SMALLINT ((juint)3) // a value too insignificant to consider widening - -const TypeInt *TypeInt::make( jint lo, jint hi, int w ) { +static int normalize_int_widen( jint lo, jint hi, int w ) { // Certain normalizations keep us sane when comparing types. // The 'SMALLINT' covers constants and also CC and its relatives. - assert(CC == NULL || (juint)(CC->_hi - CC->_lo) <= SMALLINT, "CC is truly small"); if (lo <= hi) { - if ((juint)(hi - lo) <= SMALLINT) w = Type::WidenMin; - if ((juint)(hi - lo) >= max_juint) w = Type::WidenMax; // plain int + if ((juint)(hi - lo) <= SMALLINT) w = Type::WidenMin; + if ((juint)(hi - lo) >= max_juint) w = Type::WidenMax; // TypeInt::INT + } else { + if ((juint)(lo - hi) <= SMALLINT) w = Type::WidenMin; + if ((juint)(lo - hi) >= max_juint) w = Type::WidenMin; // dual TypeInt::INT } + return w; +} + +const TypeInt *TypeInt::make( jint lo, jint hi, int w ) { + w = normalize_int_widen(lo, hi, w); return (TypeInt*)(new TypeInt(lo,hi,w))->hashcons(); } @@ -1103,14 +1111,14 @@ // Expand covered set const TypeInt *r = t->is_int(); - // (Avoid TypeInt::make, to avoid the argument normalizations it enforces.) - return (new TypeInt( MIN2(_lo,r->_lo), MAX2(_hi,r->_hi), MAX2(_widen,r->_widen) ))->hashcons(); + return make( MIN2(_lo,r->_lo), MAX2(_hi,r->_hi), MAX2(_widen,r->_widen) ); } //------------------------------xdual------------------------------------------ // Dual: reverse hi & lo; flip widen const Type *TypeInt::xdual() const { - return new TypeInt(_hi,_lo,WidenMax-_widen); + int w = normalize_int_widen(_hi,_lo, WidenMax-_widen); + return new TypeInt(_hi,_lo,w); } //------------------------------widen------------------------------------------ @@ -1202,7 +1210,7 @@ //-----------------------------filter------------------------------------------ const Type *TypeInt::filter( const Type *kills ) const { const TypeInt* ft = join(kills)->isa_int(); - if (ft == NULL || ft->_lo > ft->_hi) + if (ft == NULL || ft->empty()) return Type::TOP; // Canonical empty value if (ft->_widen < this->_widen) { // Do not allow the value of kill->_widen to affect the outcome. @@ -1304,13 +1312,21 @@ return (TypeLong*)(new TypeLong(lo,lo,WidenMin))->hashcons(); } -const TypeLong *TypeLong::make( jlong lo, jlong hi, int w ) { +static int normalize_long_widen( jlong lo, jlong hi, int w ) { // Certain normalizations keep us sane when comparing types. - // The '1' covers constants. + // The 'SMALLINT' covers constants. if (lo <= hi) { - if ((julong)(hi - lo) <= SMALLINT) w = Type::WidenMin; - if ((julong)(hi - lo) >= max_julong) w = Type::WidenMax; // plain long + if ((julong)(hi - lo) <= SMALLINT) w = Type::WidenMin; + if ((julong)(hi - lo) >= max_julong) w = Type::WidenMax; // TypeLong::LONG + } else { + if ((julong)(lo - hi) <= SMALLINT) w = Type::WidenMin; + if ((julong)(lo - hi) >= max_julong) w = Type::WidenMin; // dual TypeLong::LONG } + return w; +} + +const TypeLong *TypeLong::make( jlong lo, jlong hi, int w ) { + w = normalize_long_widen(lo, hi, w); return (TypeLong*)(new TypeLong(lo,hi,w))->hashcons(); } @@ -1351,14 +1367,14 @@ // Expand covered set const TypeLong *r = t->is_long(); // Turn into a TypeLong - // (Avoid TypeLong::make, to avoid the argument normalizations it enforces.) - return (new TypeLong( MIN2(_lo,r->_lo), MAX2(_hi,r->_hi), MAX2(_widen,r->_widen) ))->hashcons(); + return make( MIN2(_lo,r->_lo), MAX2(_hi,r->_hi), MAX2(_widen,r->_widen) ); } //------------------------------xdual------------------------------------------ // Dual: reverse hi & lo; flip widen const Type *TypeLong::xdual() const { - return new TypeLong(_hi,_lo,WidenMax-_widen); + int w = normalize_long_widen(_hi,_lo, WidenMax-_widen); + return new TypeLong(_hi,_lo,w); } //------------------------------widen------------------------------------------ @@ -1453,7 +1469,7 @@ //-----------------------------filter------------------------------------------ const Type *TypeLong::filter( const Type *kills ) const { const TypeLong* ft = join(kills)->isa_long(); - if (ft == NULL || ft->_lo > ft->_hi) + if (ft == NULL || ft->empty()) return Type::TOP; // Canonical empty value if (ft->_widen < this->_widen) { // Do not allow the value of kill->_widen to affect the outcome. diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/prims/jvm.h --- a/hotspot/src/share/vm/prims/jvm.h Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvm.h Wed Jul 05 17:18:12 2017 +0200 @@ -1044,7 +1044,22 @@ JVM_CONSTANT_Fieldref, JVM_CONSTANT_Methodref, JVM_CONSTANT_InterfaceMethodref, - JVM_CONSTANT_NameAndType + JVM_CONSTANT_NameAndType, + JVM_CONSTANT_MethodHandle = 15, // JSR 292 + JVM_CONSTANT_MethodType = 16 // JSR 292 +}; + +/* JVM_CONSTANT_MethodHandle subtypes */ +enum { + JVM_REF_getField = 1, + JVM_REF_getStatic = 2, + JVM_REF_putField = 3, + JVM_REF_putStatic = 4, + JVM_REF_invokeVirtual = 5, + JVM_REF_invokeStatic = 6, + JVM_REF_invokeSpecial = 7, + JVM_REF_newInvokeSpecial = 8, + JVM_REF_invokeInterface = 9 }; /* Used in the newarray instruction. */ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp --- a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,30 +122,8 @@ } } - // we must name the CodeBlob - some CodeBlobs already have names :- - // - stubs used by compiled code to call a (static) C++ runtime routine - // - non-relocatable machine code such as the interpreter, stubroutines, etc. - // - various singleton blobs - // - // others are unnamed so we create a name :- - // - OSR adapter (interpreter frame that has been on-stack replaced) - // - I2C and C2I adapters - const char* name = NULL; - if (cb->is_runtime_stub()) { - name = ((RuntimeStub*)cb)->name(); - } - if (cb->is_buffer_blob()) { - name = ((BufferBlob*)cb)->name(); - } - if (cb->is_deoptimization_stub() || cb->is_safepoint_stub()) { - name = ((SingletonBlob*)cb)->name(); - } - if (cb->is_uncommon_trap_stub() || cb->is_exception_stub()) { - name = ((SingletonBlob*)cb)->name(); - } - // record the CodeBlob details as a JvmtiCodeBlobDesc - JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(name, cb->instructions_begin(), + JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(cb->name(), cb->instructions_begin(), cb->instructions_end()); _global_code_blobs->append(scb); } @@ -197,7 +175,10 @@ jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) { CodeBlobCollector collector; - // first collect all the code blobs + // First collect all the code blobs. This has to be done in a + // single pass over the code cache with CodeCache_lock held because + // there isn't any safe way to iterate over regular CodeBlobs since + // they can be freed at any point. { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); collector.collect(); @@ -213,168 +194,28 @@ } -// Support class to describe a nmethod in the CodeCache - -class nmethodDesc: public CHeapObj { - private: - methodHandle _method; - address _code_begin; - address _code_end; - jvmtiAddrLocationMap* _map; - jint _map_length; - public: - nmethodDesc(methodHandle method, address code_begin, address code_end, - jvmtiAddrLocationMap* map, jint map_length) { - _method = method; - _code_begin = code_begin; - _code_end = code_end; - _map = map; - _map_length = map_length; - } - methodHandle method() const { return _method; } - address code_begin() const { return _code_begin; } - address code_end() const { return _code_end; } - jvmtiAddrLocationMap* map() const { return _map; } - jint map_length() const { return _map_length; } -}; - - -// Support class to collect a list of the nmethod CodeBlobs in -// the CodeCache. -// -// Usage :- -// -// nmethodCollector collector; -// -// collector.collect(); -// JvmtiCodeBlobDesc* blob = collector.first(); -// while (blob != NULL) { -// : -// blob = collector.next(); -// } -// -class nmethodCollector : StackObj { - private: - GrowableArray* _nmethods; // collect nmethods - int _pos; // iteration support - - // used during a collection - static GrowableArray* _global_nmethods; - static void do_nmethod(nmethod* nm); - public: - nmethodCollector() { - _nmethods = NULL; - _pos = -1; - } - ~nmethodCollector() { - if (_nmethods != NULL) { - for (int i=0; i<_nmethods->length(); i++) { - nmethodDesc* blob = _nmethods->at(i); - if (blob->map()!= NULL) { - FREE_C_HEAP_ARRAY(jvmtiAddrLocationMap, blob->map()); - } - } - delete _nmethods; - } - } - - // collect list of nmethods in the cache - void collect(); - - // iteration support - return first code blob - nmethodDesc* first() { - assert(_nmethods != NULL, "not collected"); - if (_nmethods->length() == 0) { - return NULL; - } - _pos = 0; - return _nmethods->at(0); - } - - // iteration support - return next code blob - nmethodDesc* next() { - assert(_pos >= 0, "iteration not started"); - if (_pos+1 >= _nmethods->length()) { - return NULL; - } - return _nmethods->at(++_pos); - } -}; - -// used during collection -GrowableArray* nmethodCollector::_global_nmethods; - - -// called for each nmethod in the CodeCache -// -// This function simply adds a descriptor for each nmethod to the global list. - -void nmethodCollector::do_nmethod(nmethod* nm) { - // ignore zombies - if (!nm->is_alive()) { - return; - } - - assert(nm->method() != NULL, "checking"); - - // create the location map for the nmethod. - jvmtiAddrLocationMap* map; - jint map_length; - JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nm, &map, &map_length); - - // record the nmethod details - methodHandle mh(nm->method()); - nmethodDesc* snm = new nmethodDesc(mh, - nm->code_begin(), - nm->code_end(), - map, - map_length); - _global_nmethods->append(snm); -} - -// collects a list of nmethod in the CodeCache. -// -// The created list is growable array of nmethodDesc - each one describes -// a nmethod and includs its JVMTI address location map. - -void nmethodCollector::collect() { - assert_locked_or_safepoint(CodeCache_lock); - assert(_global_nmethods == NULL, "checking"); - - // create the list - _global_nmethods = new (ResourceObj::C_HEAP) GrowableArray(100,true); - - // any a descriptor for each nmethod to the list. - CodeCache::nmethods_do(do_nmethod); - - // make the list the instance list - _nmethods = _global_nmethods; - _global_nmethods = NULL; -} - // Generate a COMPILED_METHOD_LOAD event for each nnmethod - jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* env) { HandleMark hm; - nmethodCollector collector; - - // first collect all nmethods - { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - collector.collect(); - } - // iterate over the list and post an event for each nmethod - nmethodDesc* nm_desc = collector.first(); - while (nm_desc != NULL) { - methodOop method = nm_desc->method()(); - jmethodID mid = method->jmethod_id(); - assert(mid != NULL, "checking"); - JvmtiExport::post_compiled_method_load(env, mid, - (jint)(nm_desc->code_end() - nm_desc->code_begin()), - nm_desc->code_begin(), nm_desc->map_length(), - nm_desc->map()); - nm_desc = collector.next(); + // Walk the CodeCache notifying for live nmethods. The code cache + // may be changing while this is happening which is ok since newly + // created nmethod will notify normally and nmethods which are freed + // can be safely skipped. + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + nmethod* current = CodeCache::first_nmethod(); + while (current != NULL) { + // Only notify for live nmethods + if (current->is_alive()) { + // Lock the nmethod so it can't be freed + nmethodLocker nml(current); + + // Don't hold the lock over the notify or jmethodID creation + MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + current->get_and_cache_jmethod_id(); + JvmtiExport::post_compiled_method_load(current); + } + current = CodeCache::next_nmethod(current); } return JVMTI_ERROR_NONE; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/prims/methodComparator.cpp --- a/hotspot/src/share/vm/prims/methodComparator.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/prims/methodComparator.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -163,10 +163,10 @@ case Bytecodes::_ldc : // fall through case Bytecodes::_ldc_w : { - Bytecode_loadconstant* ldc_old = Bytecode_loadconstant_at(_s_old->method()(), _s_old->bcp()); - Bytecode_loadconstant* ldc_new = Bytecode_loadconstant_at(_s_new->method()(), _s_new->bcp()); - int cpi_old = ldc_old->index(); - int cpi_new = ldc_new->index(); + Bytecode_loadconstant* ldc_old = Bytecode_loadconstant_at(_s_old->method(), _s_old->bci()); + Bytecode_loadconstant* ldc_new = Bytecode_loadconstant_at(_s_new->method(), _s_new->bci()); + int cpi_old = ldc_old->pool_index(); + int cpi_new = ldc_new->pool_index(); constantTag tag_old = _old_cp->tag_at(cpi_old); constantTag tag_new = _new_cp->tag_at(cpi_new); if (tag_old.is_int() || tag_old.is_float()) { @@ -187,12 +187,30 @@ if (strcmp(_old_cp->string_at_noresolve(cpi_old), _new_cp->string_at_noresolve(cpi_new)) != 0) return false; - } else { // tag_old should be klass - 4881222 + } else if (tag_old.is_klass() || tag_old.is_unresolved_klass()) { + // tag_old should be klass - 4881222 if (! (tag_new.is_unresolved_klass() || tag_new.is_klass())) return false; if (_old_cp->klass_at_noresolve(cpi_old) != _new_cp->klass_at_noresolve(cpi_new)) return false; + } else if (tag_old.is_method_type() && tag_new.is_method_type()) { + int mti_old = _old_cp->method_type_index_at(cpi_old); + int mti_new = _new_cp->method_type_index_at(cpi_new); + if ((_old_cp->symbol_at(mti_old) != _new_cp->symbol_at(mti_new))) + return false; + } else if (tag_old.is_method_handle() && tag_new.is_method_handle()) { + if (_old_cp->method_handle_ref_kind_at(cpi_old) != + _new_cp->method_handle_ref_kind_at(cpi_new)) + return false; + int mhi_old = _old_cp->method_handle_index_at(cpi_old); + int mhi_new = _new_cp->method_handle_index_at(cpi_new); + if ((_old_cp->uncached_klass_ref_at_noresolve(mhi_old) != _new_cp->uncached_klass_ref_at_noresolve(mhi_new)) || + (_old_cp->uncached_name_ref_at(mhi_old) != _new_cp->uncached_name_ref_at(mhi_new)) || + (_old_cp->uncached_signature_ref_at(mhi_old) != _new_cp->uncached_signature_ref_at(mhi_new))) + return false; + } else { + return false; // unknown tag } break; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1376,11 +1376,6 @@ } no_shared_spaces(); - // Set the maximum pause time goal to be a reasonable default. - if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) { - FLAG_SET_DEFAULT(MaxGCPauseMillis, 200); - } - if (FLAG_IS_DEFAULT(MarkStackSize)) { FLAG_SET_DEFAULT(MarkStackSize, 128 * TASKQUEUE_SIZE); } @@ -1513,6 +1508,9 @@ if (AggressiveOpts && FLAG_IS_DEFAULT(BiasedLockingStartupDelay)) { FLAG_SET_DEFAULT(BiasedLockingStartupDelay, 500); } + if (AggressiveOpts && FLAG_IS_DEFAULT(OptimizeStringConcat)) { + FLAG_SET_DEFAULT(OptimizeStringConcat, true); + } #endif if (AggressiveOpts) { @@ -1697,20 +1695,21 @@ status = status && verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit"); - // Check user specified sharing option conflict with Parallel GC - bool cannot_share = ((UseConcMarkSweepGC || CMSIncrementalMode) || UseG1GC || UseParNewGC || - UseParallelGC || UseParallelOldGC || - SOLARIS_ONLY(UseISM) NOT_SOLARIS(UseLargePages)); - + // Check whether user-specified sharing option conflicts with GC or page size. + // Both sharing and large pages are enabled by default on some platforms; + // large pages override sharing only if explicitly set on the command line. + const bool cannot_share = UseConcMarkSweepGC || CMSIncrementalMode || + UseG1GC || UseParNewGC || UseParallelGC || UseParallelOldGC || + UseLargePages && FLAG_IS_CMDLINE(UseLargePages); if (cannot_share) { // Either force sharing on by forcing the other options off, or // force sharing off. if (DumpSharedSpaces || ForceSharedSpaces) { jio_fprintf(defaultStream::error_stream(), - "Reverting to Serial GC because of %s\n", - ForceSharedSpaces ? " -Xshare:on" : "-Xshare:dump"); + "Using Serial GC and default page size because of %s\n", + ForceSharedSpaces ? "-Xshare:on" : "-Xshare:dump"); force_serial_gc(); - FLAG_SET_DEFAULT(SOLARIS_ONLY(UseISM) NOT_SOLARIS(UseLargePages), false); + FLAG_SET_DEFAULT(UseLargePages, false); } else { if (UseSharedSpaces && Verbose) { jio_fprintf(defaultStream::error_stream(), @@ -1719,6 +1718,8 @@ } no_shared_spaces(); } + } else if (UseLargePages && (UseSharedSpaces || DumpSharedSpaces)) { + FLAG_SET_DEFAULT(UseLargePages, false); } status = status && check_gc_consistency(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1975,7 +1975,7 @@ "Adaptive size policy maximum GC pause time goal in msec, " \ "or (G1 Only) the max. GC time per MMU time slice") \ \ - product(intx, GCPauseIntervalMillis, 500, \ + product(uintx, GCPauseIntervalMillis, 0, \ "Time slice for MMU specification") \ \ product(uintx, MaxGCMinorPauseMillis, max_uintx, \ @@ -2541,9 +2541,6 @@ "Enable String cache capabilities on String.java") \ \ /* statistics */ \ - develop(bool, UseVTune, false, \ - "enable support for Intel's VTune profiler") \ - \ develop(bool, CountCompiledCalls, false, \ "counts method invocations") \ \ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/init.cpp --- a/hotspot/src/share/vm/runtime/init.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/init.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -34,7 +34,6 @@ // Initialization done by Java thread in init_globals() void management_init(); -void vtune_init(); void bytecodes_init(); void classLoader_init(); void codeCache_init(); @@ -82,7 +81,6 @@ jint init_globals() { HandleMark hm; management_init(); - vtune_init(); bytecodes_init(); classLoader_init(); codeCache_init(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/java.cpp --- a/hotspot/src/share/vm/runtime/java.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/java.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -432,8 +432,6 @@ print_statistics(); Universe::heap()->print_tracing_info(); - VTune::exit(); - { MutexLocker ml(BeforeExit_lock); _before_exit_status = BEFORE_EXIT_DONE; BeforeExit_lock->notify_all(); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/jniHandles.cpp --- a/hotspot/src/share/vm/runtime/jniHandles.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -66,6 +66,7 @@ jobject JNIHandles::make_global(Handle obj) { + assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); jobject res = NULL; if (!obj.is_null()) { // ignore null handles @@ -81,6 +82,7 @@ jobject JNIHandles::make_weak_global(Handle obj) { + assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); jobject res = NULL; if (!obj.is_null()) { // ignore null handles diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -886,6 +886,11 @@ "%/lib/jsse.jar:" "%/lib/jce.jar:" "%/lib/charsets.jar:" + + // ## TEMPORARY hack to keep the legacy launcher working when + // ## only the boot module is installed (cf. j.l.ClassLoader) + "%/lib/modules/jdk.boot.jar:" + "%/classes"; char* sysclasspath = format_boot_path(classpath_format, home, home_len, fileSep, pathSep); if (sysclasspath == NULL) return false; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/sharedRuntime.cpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -779,7 +779,7 @@ // Find bytecode Bytecode_invoke* bytecode = Bytecode_invoke_at(caller, bci); - bc = bytecode->adjusted_invoke_code(); + bc = bytecode->java_code(); int bytecode_index = bytecode->index(); // Find receiver for non-static call @@ -2251,7 +2251,6 @@ B->name(), fingerprint->as_string(), B->instructions_begin()); - VTune::register_stub(blob_id, B->instructions_begin(), B->instructions_end()); Forte::register_stub(blob_id, B->instructions_begin(), B->instructions_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/stubCodeGenerator.cpp --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,7 +132,6 @@ _cdesc->set_end(_cgen->assembler()->pc()); assert(StubCodeDesc::_list == _cdesc, "expected order on list"); _cgen->stub_epilog(_cdesc); - VTune::register_stub(_cdesc->name(), _cdesc->begin(), _cdesc->end()); Forte::register_stub(_cdesc->name(), _cdesc->begin(), _cdesc->end()); if (JvmtiExport::should_post_dynamic_code_generated()) { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/stubRoutines.cpp --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -135,28 +135,32 @@ static void test_arraycopy_func(address func, int alignment) { int v = 0xcc; int v2 = 0x11; - jlong lbuffer[2]; - jlong lbuffer2[2]; - address buffer = (address) lbuffer; - address buffer2 = (address) lbuffer2; + jlong lbuffer[8]; + jlong lbuffer2[8]; + address fbuffer = (address) lbuffer; + address fbuffer2 = (address) lbuffer2; unsigned int i; for (i = 0; i < sizeof(lbuffer); i++) { - buffer[i] = v; buffer2[i] = v2; + fbuffer[i] = v; fbuffer2[i] = v2; } + // C++ does not guarantee jlong[] array alignment to 8 bytes. + // Use middle of array to check that memory before it is not modified. + address buffer = (address) round_to((intptr_t)&lbuffer[4], BytesPerLong); + address buffer2 = (address) round_to((intptr_t)&lbuffer2[4], BytesPerLong); // do an aligned copy ((arraycopy_fn)func)(buffer, buffer2, 0); for (i = 0; i < sizeof(lbuffer); i++) { - assert(buffer[i] == v && buffer2[i] == v2, "shouldn't have copied anything"); + assert(fbuffer[i] == v && fbuffer2[i] == v2, "shouldn't have copied anything"); } // adjust destination alignment ((arraycopy_fn)func)(buffer, buffer2 + alignment, 0); for (i = 0; i < sizeof(lbuffer); i++) { - assert(buffer[i] == v && buffer2[i] == v2, "shouldn't have copied anything"); + assert(fbuffer[i] == v && fbuffer2[i] == v2, "shouldn't have copied anything"); } // adjust source alignment ((arraycopy_fn)func)(buffer + alignment, buffer2, 0); for (i = 0; i < sizeof(lbuffer); i++) { - assert(buffer[i] == v && buffer2[i] == v2, "shouldn't have copied anything"); + assert(fbuffer[i] == v && fbuffer2[i] == v2, "shouldn't have copied anything"); } } #endif @@ -183,7 +187,7 @@ test_arraycopy_func(arrayof_##type##_arraycopy(), sizeof(HeapWord)); \ test_arraycopy_func(arrayof_##type##_disjoint_arraycopy(), sizeof(HeapWord)) - // Make sure all the arraycopy stubs properly handle zeros + // Make sure all the arraycopy stubs properly handle zero count TEST_ARRAYCOPY(jbyte); TEST_ARRAYCOPY(jshort); TEST_ARRAYCOPY(jint); @@ -191,6 +195,25 @@ #undef TEST_ARRAYCOPY +#define TEST_COPYRTN(type) \ + test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::conjoint_##type##s_atomic), sizeof(type)); \ + test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::arrayof_conjoint_##type##s), (int)MAX2(sizeof(HeapWord), sizeof(type))) + + // Make sure all the copy runtime routines properly handle zero count + TEST_COPYRTN(jbyte); + TEST_COPYRTN(jshort); + TEST_COPYRTN(jint); + TEST_COPYRTN(jlong); + +#undef TEST_COPYRTN + + test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::conjoint_words), sizeof(HeapWord)); + test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::disjoint_words), sizeof(HeapWord)); + test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::disjoint_words_atomic), sizeof(HeapWord)); + // Aligned to BytesPerLong + test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::aligned_conjoint_words), sizeof(jlong)); + test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::aligned_disjoint_words), sizeof(jlong)); + #endif } @@ -221,15 +244,13 @@ #ifndef PRODUCT SharedRuntime::_jbyte_array_copy_ctr++; // Slow-path byte array copy #endif // !PRODUCT - assert(count != 0, "count should be non-zero"); - Copy::conjoint_bytes_atomic(src, dest, count); + Copy::conjoint_jbytes_atomic(src, dest, count); JRT_END JRT_LEAF(void, StubRoutines::jshort_copy(jshort* src, jshort* dest, size_t count)) #ifndef PRODUCT SharedRuntime::_jshort_array_copy_ctr++; // Slow-path short/char array copy #endif // !PRODUCT - assert(count != 0, "count should be non-zero"); Copy::conjoint_jshorts_atomic(src, dest, count); JRT_END @@ -237,7 +258,6 @@ #ifndef PRODUCT SharedRuntime::_jint_array_copy_ctr++; // Slow-path int/float array copy #endif // !PRODUCT - assert(count != 0, "count should be non-zero"); Copy::conjoint_jints_atomic(src, dest, count); JRT_END @@ -245,7 +265,6 @@ #ifndef PRODUCT SharedRuntime::_jlong_array_copy_ctr++; // Slow-path long/double array copy #endif // !PRODUCT - assert(count != 0, "count should be non-zero"); Copy::conjoint_jlongs_atomic(src, dest, count); JRT_END @@ -263,15 +282,13 @@ #ifndef PRODUCT SharedRuntime::_jbyte_array_copy_ctr++; // Slow-path byte array copy #endif // !PRODUCT - assert(count != 0, "count should be non-zero"); - Copy::arrayof_conjoint_bytes(src, dest, count); + Copy::arrayof_conjoint_jbytes(src, dest, count); JRT_END JRT_LEAF(void, StubRoutines::arrayof_jshort_copy(HeapWord* src, HeapWord* dest, size_t count)) #ifndef PRODUCT SharedRuntime::_jshort_array_copy_ctr++; // Slow-path short/char array copy #endif // !PRODUCT - assert(count != 0, "count should be non-zero"); Copy::arrayof_conjoint_jshorts(src, dest, count); JRT_END @@ -279,7 +296,6 @@ #ifndef PRODUCT SharedRuntime::_jint_array_copy_ctr++; // Slow-path int/float array copy #endif // !PRODUCT - assert(count != 0, "count should be non-zero"); Copy::arrayof_conjoint_jints(src, dest, count); JRT_END @@ -287,7 +303,6 @@ #ifndef PRODUCT SharedRuntime::_jlong_array_copy_ctr++; // Slow-path int/float array copy #endif // !PRODUCT - assert(count != 0, "count should be non-zero"); Copy::arrayof_conjoint_jlongs(src, dest, count); JRT_END diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/sweeper.cpp --- a/hotspot/src/share/vm/runtime/sweeper.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/sweeper.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,15 +26,16 @@ # include "incls/_sweeper.cpp.incl" long NMethodSweeper::_traversals = 0; // No. of stack traversals performed -CodeBlob* NMethodSweeper::_current = NULL; // Current nmethod -int NMethodSweeper::_seen = 0 ; // No. of blobs we have currently processed in current pass of CodeCache -int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass +nmethod* NMethodSweeper::_current = NULL; // Current nmethod +int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache + +volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass +volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress. jint NMethodSweeper::_locked_seen = 0; jint NMethodSweeper::_not_entrant_seen_on_stack = 0; bool NMethodSweeper::_rescan = false; bool NMethodSweeper::_do_sweep = false; -jint NMethodSweeper::_sweep_started = 0; bool NMethodSweeper::_was_full = false; jint NMethodSweeper::_advise_to_sweep = 0; jlong NMethodSweeper::_last_was_full = 0; @@ -108,23 +109,14 @@ // code cache is filling up _last_was_full = os::javaTimeMillis(); - if (PrintMethodFlushing) { - tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + log_sweep("restart_compiler"); } } } } void NMethodSweeper::possibly_sweep() { + assert(JavaThread::current()->thread_state() == _thread_in_vm, "must run in vm mode"); if ((!MethodFlushing) || (!_do_sweep)) return; if (_invocations > 0) { @@ -133,32 +125,31 @@ if (old != 0) { return; } - sweep_code_cache(); + if (_invocations > 0) { + sweep_code_cache(); + _invocations--; + } + _sweep_started = 0; } - _sweep_started = 0; } void NMethodSweeper::sweep_code_cache() { #ifdef ASSERT jlong sweep_start; - if(PrintMethodFlushing) { + if (PrintMethodFlushing) { sweep_start = os::javaTimeMillis(); } #endif if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_blobs(), _invocations); + tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations); } - // We want to visit all nmethods after NmethodSweepFraction invocations. - // If invocation is 1 we do the rest - int todo = CodeCache::nof_blobs(); - if (_invocations > 1) { - todo = (CodeCache::nof_blobs() - _seen) / _invocations; - } - - // Compilers may check to sweep more often than stack scans happen, - // don't keep trying once it is all scanned - _invocations--; + // We want to visit all nmethods after NmethodSweepFraction + // invocations so divide the remaining number of nmethods by the + // remaining number of invocations. This is only an estimate since + // the number of nmethods changes during the sweep so the final + // stage must iterate until it there are no more nmethods. + int todo = (CodeCache::nof_nmethods() - _seen) / _invocations; assert(!SafepointSynchronize::is_at_safepoint(), "should not be in safepoint when we get here"); assert(!CodeCache_lock->owned_by_self(), "just checking"); @@ -166,26 +157,25 @@ { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - for(int i = 0; i < todo && _current != NULL; i++) { + // The last invocation iterates until there are no more nmethods + for (int i = 0; (i < todo || _invocations == 1) && _current != NULL; i++) { - // Since we will give up the CodeCache_lock, always skip ahead to an nmethod. - // Other blobs can be deleted by other threads - // Read next before we potentially delete current - CodeBlob* next = CodeCache::next_nmethod(_current); + // Since we will give up the CodeCache_lock, always skip ahead + // to the next nmethod. Other blobs can be deleted by other + // threads but nmethods are only reclaimed by the sweeper. + nmethod* next = CodeCache::next_nmethod(_current); // Now ready to process nmethod and give up CodeCache_lock { MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - process_nmethod((nmethod *)_current); + process_nmethod(_current); } _seen++; _current = next; } + } - // Skip forward to the next nmethod (if any). Code blobs other than nmethods - // can be freed async to us and make _current invalid while we sleep. - _current = CodeCache::next_nmethod(_current); - } + assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache"); if (_current == NULL && !_rescan && (_locked_seen || _not_entrant_seen_on_stack)) { // we've completed a scan without making progress but there were @@ -205,6 +195,10 @@ tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, sweep_end - sweep_start); } #endif + + if (_invocations == 1) { + log_sweep("finished"); + } } @@ -227,7 +221,7 @@ if (nm->is_zombie()) { // If it is first time, we see nmethod then we mark it. Otherwise, // we reclame it. When we have seen a zombie method twice, we know that - // there are no inline caches that referes to it. + // there are no inline caches that refer to it. if (nm->is_marked_for_reclamation()) { assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); if (PrintMethodFlushing && Verbose) { @@ -324,16 +318,8 @@ jlong curr_interval = now - _last_was_full; if (curr_interval < max_interval) { _rescan = true; - if (PrintMethodFlushing) { - tty->print_cr("### handle full too often, turning off compiler"); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("disable_compiler flushing_interval='" UINT64_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - curr_interval/1000, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + log_sweep("disable_compiler", "flushing_interval='" UINT64_FORMAT "'", + curr_interval/1000); return; } } @@ -353,17 +339,7 @@ if ((!was_full()) && (is_full)) { if (!CodeCache::needs_flushing()) { - if (PrintMethodFlushing) { - tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + log_sweep("restart_compiler"); CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); return; } @@ -372,17 +348,7 @@ // Traverse the code cache trying to dump the oldest nmethods uint curr_max_comp_id = CompileBroker::get_compilation_id(); uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked; - if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Cleaning code cache: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("start_cleaning_code_cache live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + log_sweep("start_cleaning"); nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); jint disconnected = 0; @@ -415,13 +381,9 @@ nm = CodeCache::alive_nmethod(CodeCache::next(nm)); } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("stop_cleaning_code_cache disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - disconnected, made_not_entrant, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + log_sweep("stop_cleaning", + "disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'", + disconnected, made_not_entrant); // Shut off compiler. Sweeper will start over with a new stack scan and // traversal cycle and turn it back on if it clears enough space. @@ -439,3 +401,38 @@ } #endif } + + +// Print out some state information about the current sweep and the +// state of the code cache if it's requested. +void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) { + if (PrintMethodFlushing) { + ttyLocker ttyl; + tty->print("### sweeper: %s ", msg); + if (format != NULL) { + va_list ap; + va_start(ap, format); + tty->vprint(format, ap); + va_end(ap); + } + tty->print_cr(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'" + " adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", + CodeCache::nof_blobs(), CodeCache::nof_nmethods(), CodeCache::nof_adapters(), CodeCache::unallocated_capacity()); + } + + if (LogCompilation && (xtty != NULL)) { + ttyLocker ttyl; + xtty->begin_elem("sweeper state='%s' traversals='" INTX_FORMAT "' ", msg, (intx)traversal_count()); + if (format != NULL) { + va_list ap; + va_start(ap, format); + xtty->vprint(format, ap); + va_end(ap); + } + xtty->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'" + " adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", + CodeCache::nof_blobs(), CodeCache::nof_nmethods(), CodeCache::nof_adapters(), CodeCache::unallocated_capacity()); + xtty->stamp(); + xtty->end_elem(); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/sweeper.hpp --- a/hotspot/src/share/vm/runtime/sweeper.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/sweeper.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,14 +29,15 @@ class NMethodSweeper : public AllStatic { static long _traversals; // Stack traversal count - static CodeBlob* _current; // Current nmethod + static nmethod* _current; // Current nmethod static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache - static int _invocations; // No. of invocations left until we are completed with this pass + + static volatile int _invocations; // No. of invocations left until we are completed with this pass + static volatile int _sweep_started; // Flag to control conc sweeper static bool _rescan; // Indicates that we should do a full rescan of the // of the code cache looking for work to do. static bool _do_sweep; // Flag to skip the conc sweep if no stack scan happened - static jint _sweep_started; // Flag to control conc sweeper static int _locked_seen; // Number of locked nmethods encountered during the scan static int _not_entrant_seen_on_stack; // Number of not entrant nmethod were are still on stack @@ -47,6 +48,9 @@ static long _was_full_traversal; // trav number at last emergency unloading static void process_nmethod(nmethod *nm); + + static void log_sweep(const char* msg, const char* format = NULL, ...); + public: static long traversal_count() { return _traversals; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/synchronizer.cpp --- a/hotspot/src/share/vm/runtime/synchronizer.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -747,6 +747,8 @@ ObjectMonitor * ObjectSynchronizer::gBlockList = NULL ; ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL ; +ObjectMonitor * volatile ObjectSynchronizer::gOmInUseList = NULL ; +int ObjectSynchronizer::gOmInUseCount = 0; static volatile intptr_t ListLock = 0 ; // protects global monitor free-list cache static volatile int MonitorFreeCount = 0 ; // # on gFreeList static volatile int MonitorPopulation = 0 ; // # Extant -- in circulation @@ -826,6 +828,22 @@ } } } +/* Too slow for general assert or debug +void ObjectSynchronizer::verifyInUse (Thread *Self) { + ObjectMonitor* mid; + int inusetally = 0; + for (mid = Self->omInUseList; mid != NULL; mid = mid->FreeNext) { + inusetally ++; + } + assert(inusetally == Self->omInUseCount, "inuse count off"); + + int freetally = 0; + for (mid = Self->omFreeList; mid != NULL; mid = mid->FreeNext) { + freetally ++; + } + assert(freetally == Self->omFreeCount, "free count off"); +} +*/ ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) { // A large MAXPRIVATE value reduces both list lock contention @@ -853,6 +871,9 @@ m->FreeNext = Self->omInUseList; Self->omInUseList = m; Self->omInUseCount ++; + // verifyInUse(Self); + } else { + m->FreeNext = NULL; } return m ; } @@ -874,13 +895,12 @@ guarantee (take->object() == NULL, "invariant") ; guarantee (!take->is_busy(), "invariant") ; take->Recycle() ; - omRelease (Self, take) ; + omRelease (Self, take, false) ; } Thread::muxRelease (&ListLock) ; Self->omFreeProvision += 1 + (Self->omFreeProvision/2) ; if (Self->omFreeProvision > MAXPRIVATE ) Self->omFreeProvision = MAXPRIVATE ; TEVENT (omFirst - reprovision) ; - continue ; const int mx = MonitorBound ; if (mx > 0 && (MonitorPopulation-MonitorFreeCount) > mx) { @@ -961,11 +981,34 @@ // That is, *not* one-at-a-time. -void ObjectSynchronizer::omRelease (Thread * Self, ObjectMonitor * m) { +void ObjectSynchronizer::omRelease (Thread * Self, ObjectMonitor * m, bool fromPerThreadAlloc) { guarantee (m->object() == NULL, "invariant") ; - m->FreeNext = Self->omFreeList ; - Self->omFreeList = m ; - Self->omFreeCount ++ ; + + // Remove from omInUseList + if (MonitorInUseLists && fromPerThreadAlloc) { + ObjectMonitor* curmidinuse = NULL; + for (ObjectMonitor* mid = Self->omInUseList; mid != NULL; ) { + if (m == mid) { + // extract from per-thread in-use-list + if (mid == Self->omInUseList) { + Self->omInUseList = mid->FreeNext; + } else if (curmidinuse != NULL) { + curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist + } + Self->omInUseCount --; + // verifyInUse(Self); + break; + } else { + curmidinuse = mid; + mid = mid->FreeNext; + } + } + } + + // FreeNext is used for both onInUseList and omFreeList, so clear old before setting new + m->FreeNext = Self->omFreeList ; + Self->omFreeList = m ; + Self->omFreeCount ++ ; } // Return the monitors of a moribund thread's local free list to @@ -975,6 +1018,10 @@ // consecutive STW safepoints. Relatedly, we might decay // omFreeProvision at STW safepoints. // +// Also return the monitors of a moribund thread"s omInUseList to +// a global gOmInUseList under the global list lock so these +// will continue to be scanned. +// // We currently call omFlush() from the Thread:: dtor _after the thread // has been excised from the thread list and is no longer a mutator. // That means that omFlush() can run concurrently with a safepoint and @@ -987,24 +1034,50 @@ void ObjectSynchronizer::omFlush (Thread * Self) { ObjectMonitor * List = Self->omFreeList ; // Null-terminated SLL Self->omFreeList = NULL ; - if (List == NULL) return ; ObjectMonitor * Tail = NULL ; - ObjectMonitor * s ; int Tally = 0; - for (s = List ; s != NULL ; s = s->FreeNext) { - Tally ++ ; - Tail = s ; - guarantee (s->object() == NULL, "invariant") ; - guarantee (!s->is_busy(), "invariant") ; - s->set_owner (NULL) ; // redundant but good hygiene - TEVENT (omFlush - Move one) ; + if (List != NULL) { + ObjectMonitor * s ; + for (s = List ; s != NULL ; s = s->FreeNext) { + Tally ++ ; + Tail = s ; + guarantee (s->object() == NULL, "invariant") ; + guarantee (!s->is_busy(), "invariant") ; + s->set_owner (NULL) ; // redundant but good hygiene + TEVENT (omFlush - Move one) ; + } + guarantee (Tail != NULL && List != NULL, "invariant") ; } - guarantee (Tail != NULL && List != NULL, "invariant") ; + ObjectMonitor * InUseList = Self->omInUseList; + ObjectMonitor * InUseTail = NULL ; + int InUseTally = 0; + if (InUseList != NULL) { + Self->omInUseList = NULL; + ObjectMonitor *curom; + for (curom = InUseList; curom != NULL; curom = curom->FreeNext) { + InUseTail = curom; + InUseTally++; + } +// TODO debug + assert(Self->omInUseCount == InUseTally, "inuse count off"); + Self->omInUseCount = 0; + guarantee (InUseTail != NULL && InUseList != NULL, "invariant"); + } + Thread::muxAcquire (&ListLock, "omFlush") ; - Tail->FreeNext = gFreeList ; - gFreeList = List ; - MonitorFreeCount += Tally; + if (Tail != NULL) { + Tail->FreeNext = gFreeList ; + gFreeList = List ; + MonitorFreeCount += Tally; + } + + if (InUseTail != NULL) { + InUseTail->FreeNext = gOmInUseList; + gOmInUseList = InUseList; + gOmInUseCount += InUseTally; + } + Thread::muxRelease (&ListLock) ; TEVENT (omFlush) ; } @@ -1166,7 +1239,6 @@ // We do this before the CAS in order to minimize the length of time // in which INFLATING appears in the mark. m->Recycle(); - m->FreeNext = NULL ; m->_Responsible = NULL ; m->OwnerIsThread = 0 ; m->_recursions = 0 ; @@ -1174,7 +1246,7 @@ markOop cmp = (markOop) Atomic::cmpxchg_ptr (markOopDesc::INFLATING(), object->mark_addr(), mark) ; if (cmp != mark) { - omRelease (Self, m) ; + omRelease (Self, m, true) ; continue ; // Interference -- just retry } @@ -1262,7 +1334,6 @@ m->set_object(object); m->OwnerIsThread = 1 ; m->_recursions = 0 ; - m->FreeNext = NULL ; m->_Responsible = NULL ; m->_SpinDuration = Knob_SpinLimit ; // consider: keep metastats by type/class @@ -1271,7 +1342,7 @@ m->set_owner (NULL) ; m->OwnerIsThread = 0 ; m->Recycle() ; - omRelease (Self, m) ; + omRelease (Self, m, true) ; m = NULL ; continue ; // interference - the markword changed - just retry. @@ -1852,6 +1923,10 @@ // only scans the per-thread inuse lists. omAlloc() puts all // assigned monitors on the per-thread list. deflate_idle_monitors() // returns the non-busy monitors to the global free list. +// When a thread dies, omFlush() adds the list of active monitors for +// that thread to a global gOmInUseList acquiring the +// global list lock. deflate_idle_monitors() acquires the global +// list lock to scan for non-busy monitors to the global free list. // An alternative could have used a single global inuse list. The // downside would have been the additional cost of acquiring the global list lock // for every omAlloc(). @@ -1904,6 +1979,7 @@ if (*FreeHeadp == NULL) *FreeHeadp = mid; if (*FreeTailp != NULL) { ObjectMonitor * prevtail = *FreeTailp; + assert(prevtail->FreeNext == NULL, "cleaned up deflated?"); // TODO KK prevtail->FreeNext = mid; } *FreeTailp = mid; @@ -1912,6 +1988,39 @@ return deflated; } +// Caller acquires ListLock +int ObjectSynchronizer::walk_monitor_list(ObjectMonitor** listheadp, + ObjectMonitor** FreeHeadp, ObjectMonitor** FreeTailp) { + ObjectMonitor* mid; + ObjectMonitor* next; + ObjectMonitor* curmidinuse = NULL; + int deflatedcount = 0; + + for (mid = *listheadp; mid != NULL; ) { + oop obj = (oop) mid->object(); + bool deflated = false; + if (obj != NULL) { + deflated = deflate_monitor(mid, obj, FreeHeadp, FreeTailp); + } + if (deflated) { + // extract from per-thread in-use-list + if (mid == *listheadp) { + *listheadp = mid->FreeNext; + } else if (curmidinuse != NULL) { + curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist + } + next = mid->FreeNext; + mid->FreeNext = NULL; // This mid is current tail in the FreeHead list + mid = next; + deflatedcount++; + } else { + curmidinuse = mid; + mid = mid->FreeNext; + } + } + return deflatedcount; +} + void ObjectSynchronizer::deflate_idle_monitors() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); int nInuse = 0 ; // currently associated with objects @@ -1929,36 +2038,25 @@ Thread::muxAcquire (&ListLock, "scavenge - return") ; if (MonitorInUseLists) { - ObjectMonitor* mid; - ObjectMonitor* next; - ObjectMonitor* curmidinuse; + int inUse = 0; for (JavaThread* cur = Threads::first(); cur != NULL; cur = cur->next()) { - curmidinuse = NULL; - for (mid = cur->omInUseList; mid != NULL; ) { - oop obj = (oop) mid->object(); - deflated = false; - if (obj != NULL) { - deflated = deflate_monitor(mid, obj, &FreeHead, &FreeTail); - } - if (deflated) { - // extract from per-thread in-use-list - if (mid == cur->omInUseList) { - cur->omInUseList = mid->FreeNext; - } else if (curmidinuse != NULL) { - curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist - } - next = mid->FreeNext; - mid->FreeNext = NULL; // This mid is current tail in the FreeHead list - mid = next; - cur->omInUseCount--; - nScavenged ++ ; - } else { - curmidinuse = mid; - mid = mid->FreeNext; - nInuse ++; - } + nInCirculation+= cur->omInUseCount; + int deflatedcount = walk_monitor_list(cur->omInUseList_addr(), &FreeHead, &FreeTail); + cur->omInUseCount-= deflatedcount; + // verifyInUse(cur); + nScavenged += deflatedcount; + nInuse += cur->omInUseCount; } - } + + // For moribund threads, scan gOmInUseList + if (gOmInUseList) { + nInCirculation += gOmInUseCount; + int deflatedcount = walk_monitor_list((ObjectMonitor **)&gOmInUseList, &FreeHead, &FreeTail); + gOmInUseCount-= deflatedcount; + nScavenged += deflatedcount; + nInuse += gOmInUseCount; + } + } else for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) { // Iterate over all extant monitors - Scavenge all idle monitors. assert(block->object() == CHAINMARKER, "must be a block header"); diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/synchronizer.hpp --- a/hotspot/src/share/vm/runtime/synchronizer.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/synchronizer.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -122,8 +122,9 @@ static void reenter (Handle obj, intptr_t recursion, TRAPS); // thread-specific and global objectMonitor free list accessors +// static void verifyInUse (Thread * Self) ; too slow for general assert/debug static ObjectMonitor * omAlloc (Thread * Self) ; - static void omRelease (Thread * Self, ObjectMonitor * m) ; + static void omRelease (Thread * Self, ObjectMonitor * m, bool FromPerThreadAlloc) ; static void omFlush (Thread * Self) ; // Inflate light weight monitor to heavy weight monitor @@ -150,6 +151,9 @@ // Basically we deflate all monitors that are not busy. // An adaptive profile-based deflation policy could be used if needed static void deflate_idle_monitors(); + static int walk_monitor_list(ObjectMonitor** listheadp, + ObjectMonitor** FreeHeadp, + ObjectMonitor** FreeTailp); static bool deflate_monitor(ObjectMonitor* mid, oop obj, ObjectMonitor** FreeHeadp, ObjectMonitor** FreeTailp); static void oops_do(OopClosure* f); @@ -163,6 +167,8 @@ enum { _BLOCKSIZE = 128 }; static ObjectMonitor* gBlockList; static ObjectMonitor * volatile gFreeList; + static ObjectMonitor * volatile gOmInUseList; // for moribund thread, so monitors they inflated still get scanned + static int gOmInUseCount; public: static void Initialize () ; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -2700,7 +2700,7 @@ if (in_bytes(size_in_bytes) != 0) { _popframe_preserved_args = NEW_C_HEAP_ARRAY(char, in_bytes(size_in_bytes)); _popframe_preserved_args_size = in_bytes(size_in_bytes); - Copy::conjoint_bytes(start, _popframe_preserved_args, _popframe_preserved_args_size); + Copy::conjoint_jbytes(start, _popframe_preserved_args, _popframe_preserved_args_size); } } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/thread.hpp --- a/hotspot/src/share/vm/runtime/thread.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/thread.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -270,6 +270,7 @@ static void interrupt(Thread* thr); static bool is_interrupted(Thread* thr, bool clear_interrupted); + ObjectMonitor** omInUseList_addr() { return (ObjectMonitor **)&omInUseList; } Monitor* SR_lock() const { return _SR_lock; } bool has_async_exception() const { return (_suspend_flags & _has_async_exception) != 0; } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/vframeArray.cpp --- a/hotspot/src/share/vm/runtime/vframeArray.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/vframeArray.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -355,9 +355,9 @@ } else { base = iframe()->interpreter_frame_expression_stack(); } - Copy::conjoint_bytes(saved_args, - base, - popframe_preserved_args_size_in_bytes); + Copy::conjoint_jbytes(saved_args, + base, + popframe_preserved_args_size_in_bytes); thread->popframe_free_preserved_args(); } } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/virtualspace.cpp --- a/hotspot/src/share/vm/runtime/virtualspace.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -111,6 +111,35 @@ return result; } +// Helper method. +static bool failed_to_reserve_as_requested(char* base, char* requested_address, + const size_t size, bool special) +{ + if (base == requested_address || requested_address == NULL) + return false; // did not fail + + if (base != NULL) { + // Different reserve address may be acceptable in other cases + // but for compressed oops heap should be at requested address. + assert(UseCompressedOops, "currently requested address used only for compressed oops"); + if (PrintCompressedOopsMode) { + tty->cr(); + tty->print_cr("Reserved memory at not requested address: " PTR_FORMAT " vs " PTR_FORMAT, base, requested_address); + } + // OS ignored requested address. Try different address. + if (special) { + if (!os::release_memory_special(base, size)) { + fatal("os::release_memory_special failed"); + } + } else { + if (!os::release_memory(base, size)) { + fatal("os::release_memory failed"); + } + } + } + return true; +} + ReservedSpace::ReservedSpace(const size_t prefix_size, const size_t prefix_align, const size_t suffix_size, @@ -129,6 +158,10 @@ assert((suffix_align & prefix_align - 1) == 0, "suffix_align not divisible by prefix_align"); + // Assert that if noaccess_prefix is used, it is the same as prefix_align. + assert(noaccess_prefix == 0 || + noaccess_prefix == prefix_align, "noaccess prefix wrong"); + // Add in noaccess_prefix to prefix_size; const size_t adjusted_prefix_size = prefix_size + noaccess_prefix; const size_t size = adjusted_prefix_size + suffix_size; @@ -150,15 +183,16 @@ _noaccess_prefix = 0; _executable = false; - // Assert that if noaccess_prefix is used, it is the same as prefix_align. - assert(noaccess_prefix == 0 || - noaccess_prefix == prefix_align, "noaccess prefix wrong"); - // Optimistically try to reserve the exact size needed. char* addr; if (requested_address != 0) { - addr = os::attempt_reserve_memory_at(size, - requested_address-noaccess_prefix); + requested_address -= noaccess_prefix; // adjust address + assert(requested_address != NULL, "huge noaccess prefix?"); + addr = os::attempt_reserve_memory_at(size, requested_address); + if (failed_to_reserve_as_requested(addr, requested_address, size, false)) { + // OS ignored requested address. Try different address. + addr = NULL; + } } else { addr = os::reserve_memory(size, NULL, prefix_align); } @@ -222,11 +256,20 @@ bool special = large && !os::can_commit_large_page_memory(); char* base = NULL; + if (requested_address != 0) { + requested_address -= noaccess_prefix; // adjust requested address + assert(requested_address != NULL, "huge noaccess prefix?"); + } + if (special) { base = os::reserve_memory_special(size, requested_address, executable); if (base != NULL) { + if (failed_to_reserve_as_requested(base, requested_address, size, true)) { + // OS ignored requested address. Try different address. + return; + } // Check alignment constraints if (alignment > 0) { assert((uintptr_t) base % alignment == 0, @@ -235,6 +278,13 @@ _special = true; } else { // failed; try to reserve regular memory below + if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || + !FLAG_IS_DEFAULT(LargePageSizeInBytes))) { + if (PrintCompressedOopsMode) { + tty->cr(); + tty->print_cr("Reserve regular memory without large pages."); + } + } } } @@ -248,8 +298,11 @@ // important. If available space is not detected, return NULL. if (requested_address != 0) { - base = os::attempt_reserve_memory_at(size, - requested_address-noaccess_prefix); + base = os::attempt_reserve_memory_at(size, requested_address); + if (failed_to_reserve_as_requested(base, requested_address, size, false)) { + // OS ignored requested address. Try different address. + base = NULL; + } } else { base = os::reserve_memory(size, NULL, alignment); } @@ -365,7 +418,12 @@ } void ReservedSpace::protect_noaccess_prefix(const size_t size) { - // If there is noaccess prefix, return. + assert( (_noaccess_prefix != 0) == (UseCompressedOops && _base != NULL && + (size_t(_base + _size) > OopEncodingHeapMax) && + Universe::narrow_oop_use_implicit_null_checks()), + "noaccess_prefix should be used only with non zero based compressed oops"); + + // If there is no noaccess prefix, return. if (_noaccess_prefix == 0) return; assert(_noaccess_prefix >= (size_t)os::vm_page_size(), @@ -377,6 +435,10 @@ _special)) { fatal("cannot protect protection page"); } + if (PrintCompressedOopsMode) { + tty->cr(); + tty->print_cr("Protected page at the reserved heap base: " PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix); + } _base += _noaccess_prefix; _size -= _noaccess_prefix; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -614,7 +614,6 @@ /* NMethods (NOTE: incomplete, but only a little) */ \ /**************************************************/ \ \ - static_field(nmethod, _zombie_instruction_size, int) \ nonstatic_field(nmethod, _method, methodOop) \ nonstatic_field(nmethod, _entry_bci, int) \ nonstatic_field(nmethod, _osr_link, nmethod*) \ diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/runtime/vtune.hpp --- a/hotspot/src/share/vm/runtime/vtune.hpp Wed Jul 05 17:17:22 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. - * 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. - * - */ - -// Interface to Intel's VTune profiler. - -class VTune : AllStatic { - public: - static void create_nmethod(nmethod* nm); // register newly created nmethod - static void delete_nmethod(nmethod* nm); // unregister nmethod before discarding it - - static void register_stub(const char* name, address start, address end); - // register internal VM stub - static void start_GC(); // start/end of GC or scavenge - static void end_GC(); - - static void start_class_load(); // start/end of class loading - static void end_class_load(); - - static void exit(); // VM exit -}; - - -// helper objects -class VTuneGCMarker : StackObj { - public: - VTuneGCMarker() { VTune::start_GC(); } - ~VTuneGCMarker() { VTune::end_GC(); } -}; - -class VTuneClassLoadMarker : StackObj { - public: - VTuneClassLoadMarker() { VTune::start_class_load(); } - ~VTuneClassLoadMarker() { VTune::end_class_load(); } -}; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/utilities/constantTag.cpp --- a/hotspot/src/share/vm/utilities/constantTag.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/utilities/constantTag.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -28,56 +28,85 @@ #ifndef PRODUCT void constantTag::print_on(outputStream* st) const { + st->print(internal_name()); +} + +#endif // PRODUCT + +BasicType constantTag::basic_type() const { switch (_tag) { - case JVM_CONSTANT_Class : - st->print("Class"); - break; - case JVM_CONSTANT_Fieldref : - st->print("Field"); - break; - case JVM_CONSTANT_Methodref : - st->print("Method"); - break; - case JVM_CONSTANT_InterfaceMethodref : - st->print("InterfaceMethod"); - break; - case JVM_CONSTANT_String : - st->print("String"); - break; case JVM_CONSTANT_Integer : - st->print("Integer"); - break; + return T_INT; case JVM_CONSTANT_Float : - st->print("Float"); - break; + return T_FLOAT; case JVM_CONSTANT_Long : - st->print("Long"); - break; + return T_LONG; case JVM_CONSTANT_Double : - st->print("Double"); - break; - case JVM_CONSTANT_NameAndType : - st->print("NameAndType"); - break; - case JVM_CONSTANT_Utf8 : - st->print("Utf8"); - break; + return T_DOUBLE; + + case JVM_CONSTANT_Class : + case JVM_CONSTANT_String : case JVM_CONSTANT_UnresolvedClass : - st->print("Unresolved class"); - break; + case JVM_CONSTANT_UnresolvedClassInError : case JVM_CONSTANT_ClassIndex : - st->print("Unresolved class index"); - break; case JVM_CONSTANT_UnresolvedString : - st->print("Unresolved string"); - break; case JVM_CONSTANT_StringIndex : - st->print("Unresolved string index"); - break; + case JVM_CONSTANT_MethodHandle : + case JVM_CONSTANT_MethodType : + case JVM_CONSTANT_Object : + return T_OBJECT; default: ShouldNotReachHere(); - break; + return T_ILLEGAL; } } -#endif // PRODUCT + + +const char* constantTag::internal_name() const { + switch (_tag) { + case JVM_CONSTANT_Invalid : + return "Invalid index"; + case JVM_CONSTANT_Class : + return "Class"; + case JVM_CONSTANT_Fieldref : + return "Field"; + case JVM_CONSTANT_Methodref : + return "Method"; + case JVM_CONSTANT_InterfaceMethodref : + return "InterfaceMethod"; + case JVM_CONSTANT_String : + return "String"; + case JVM_CONSTANT_Integer : + return "Integer"; + case JVM_CONSTANT_Float : + return "Float"; + case JVM_CONSTANT_Long : + return "Long"; + case JVM_CONSTANT_Double : + return "Double"; + case JVM_CONSTANT_NameAndType : + return "NameAndType"; + case JVM_CONSTANT_MethodHandle : + return "MethodHandle"; + case JVM_CONSTANT_MethodType : + return "MethodType"; + case JVM_CONSTANT_Object : + return "Object"; + case JVM_CONSTANT_Utf8 : + return "Utf8"; + case JVM_CONSTANT_UnresolvedClass : + return "Unresolved Class"; + case JVM_CONSTANT_UnresolvedClassInError : + return "Unresolved Class Error"; + case JVM_CONSTANT_ClassIndex : + return "Unresolved Class Index"; + case JVM_CONSTANT_UnresolvedString : + return "Unresolved String"; + case JVM_CONSTANT_StringIndex : + return "Unresolved String Index"; + default: + ShouldNotReachHere(); + return "Illegal"; + } +} diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/utilities/constantTag.hpp --- a/hotspot/src/share/vm/utilities/constantTag.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/utilities/constantTag.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -78,13 +78,24 @@ bool is_field_or_method() const { return is_field() || is_method() || is_interface_method(); } bool is_symbol() const { return is_utf8(); } + bool is_method_type() const { return _tag == JVM_CONSTANT_MethodType; } + bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; } + + constantTag() { + _tag = JVM_CONSTANT_Invalid; + } constantTag(jbyte tag) { assert((tag >= 0 && tag <= JVM_CONSTANT_NameAndType) || + (tag >= JVM_CONSTANT_MethodHandle && tag <= JVM_CONSTANT_MethodType) || (tag >= JVM_CONSTANT_InternalMin && tag <= JVM_CONSTANT_InternalMax), "Invalid constant tag"); _tag = tag; } jbyte value() { return _tag; } + BasicType basic_type() const; // if used with ldc, what kind of value gets pushed? + + const char* internal_name() const; // for error reporting + void print_on(outputStream* st) const PRODUCT_RETURN; }; diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/utilities/copy.cpp --- a/hotspot/src/share/vm/utilities/copy.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/utilities/copy.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -48,7 +48,7 @@ Copy::conjoint_jshorts_atomic((jshort*) src, (jshort*) dst, size / sizeof(jshort)); } else { // Not aligned, so no need to be atomic. - Copy::conjoint_bytes((void*) src, (void*) dst, size); + Copy::conjoint_jbytes((void*) src, (void*) dst, size); } } diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/utilities/copy.hpp --- a/hotspot/src/share/vm/utilities/copy.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/utilities/copy.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -73,6 +73,9 @@ // whole alignment units. E.g., if BytesPerLong is 2x word alignment, an odd // count may copy an extra word. In the arrayof case, we are allowed to copy // only the number of copy units specified. + // + // All callees check count for 0. + // // HeapWords @@ -99,7 +102,6 @@ // Object-aligned words, conjoint, not atomic on each word static void aligned_conjoint_words(HeapWord* from, HeapWord* to, size_t count) { assert_params_aligned(from, to); - assert_non_zero(count); pd_aligned_conjoint_words(from, to, count); } @@ -107,49 +109,42 @@ static void aligned_disjoint_words(HeapWord* from, HeapWord* to, size_t count) { assert_params_aligned(from, to); assert_disjoint(from, to, count); - assert_non_zero(count); pd_aligned_disjoint_words(from, to, count); } // bytes, jshorts, jints, jlongs, oops // bytes, conjoint, not atomic on each byte (not that it matters) - static void conjoint_bytes(void* from, void* to, size_t count) { - assert_non_zero(count); + static void conjoint_jbytes(void* from, void* to, size_t count) { pd_conjoint_bytes(from, to, count); } // bytes, conjoint, atomic on each byte (not that it matters) - static void conjoint_bytes_atomic(void* from, void* to, size_t count) { - assert_non_zero(count); + static void conjoint_jbytes_atomic(void* from, void* to, size_t count) { pd_conjoint_bytes(from, to, count); } // jshorts, conjoint, atomic on each jshort static void conjoint_jshorts_atomic(jshort* from, jshort* to, size_t count) { assert_params_ok(from, to, LogBytesPerShort); - assert_non_zero(count); pd_conjoint_jshorts_atomic(from, to, count); } // jints, conjoint, atomic on each jint static void conjoint_jints_atomic(jint* from, jint* to, size_t count) { assert_params_ok(from, to, LogBytesPerInt); - assert_non_zero(count); pd_conjoint_jints_atomic(from, to, count); } // jlongs, conjoint, atomic on each jlong static void conjoint_jlongs_atomic(jlong* from, jlong* to, size_t count) { assert_params_ok(from, to, LogBytesPerLong); - assert_non_zero(count); pd_conjoint_jlongs_atomic(from, to, count); } // oops, conjoint, atomic on each oop static void conjoint_oops_atomic(oop* from, oop* to, size_t count) { assert_params_ok(from, to, LogBytesPerHeapOop); - assert_non_zero(count); pd_conjoint_oops_atomic(from, to, count); } @@ -157,7 +152,6 @@ static void conjoint_oops_atomic(narrowOop* from, narrowOop* to, size_t count) { assert(sizeof(narrowOop) == sizeof(jint), "this cast is wrong"); assert_params_ok(from, to, LogBytesPerInt); - assert_non_zero(count); pd_conjoint_jints_atomic((jint*)from, (jint*)to, count); } @@ -168,36 +162,31 @@ static void conjoint_memory_atomic(void* from, void* to, size_t size); // bytes, conjoint array, atomic on each byte (not that it matters) - static void arrayof_conjoint_bytes(HeapWord* from, HeapWord* to, size_t count) { - assert_non_zero(count); + static void arrayof_conjoint_jbytes(HeapWord* from, HeapWord* to, size_t count) { pd_arrayof_conjoint_bytes(from, to, count); } // jshorts, conjoint array, atomic on each jshort static void arrayof_conjoint_jshorts(HeapWord* from, HeapWord* to, size_t count) { assert_params_ok(from, to, LogBytesPerShort); - assert_non_zero(count); pd_arrayof_conjoint_jshorts(from, to, count); } // jints, conjoint array, atomic on each jint static void arrayof_conjoint_jints(HeapWord* from, HeapWord* to, size_t count) { assert_params_ok(from, to, LogBytesPerInt); - assert_non_zero(count); pd_arrayof_conjoint_jints(from, to, count); } // jlongs, conjoint array, atomic on each jlong static void arrayof_conjoint_jlongs(HeapWord* from, HeapWord* to, size_t count) { assert_params_ok(from, to, LogBytesPerLong); - assert_non_zero(count); pd_arrayof_conjoint_jlongs(from, to, count); } // oops, conjoint array, atomic on each oop static void arrayof_conjoint_oops(HeapWord* from, HeapWord* to, size_t count) { assert_params_ok(from, to, LogBytesPerHeapOop); - assert_non_zero(count); pd_arrayof_conjoint_oops(from, to, count); } @@ -319,14 +308,6 @@ #endif } - static void assert_non_zero(size_t count) { -#ifdef ASSERT - if (count == 0) { - basic_fatal("count must be non-zero"); - } -#endif - } - static void assert_byte_count_ok(size_t byte_count, size_t unit_size) { #ifdef ASSERT if ((size_t)round_to(byte_count, unit_size) != byte_count) { diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/utilities/taskqueue.cpp --- a/hotspot/src/share/vm/utilities/taskqueue.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/utilities/taskqueue.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -182,73 +182,3 @@ _index < objArrayOop(_obj)->length(); } #endif // ASSERT - -bool RegionTaskQueueWithOverflow::is_empty() { - return (_region_queue.size() == 0) && - (_overflow_stack->length() == 0); -} - -bool RegionTaskQueueWithOverflow::stealable_is_empty() { - return _region_queue.size() == 0; -} - -bool RegionTaskQueueWithOverflow::overflow_is_empty() { - return _overflow_stack->length() == 0; -} - -void RegionTaskQueueWithOverflow::initialize() { - _region_queue.initialize(); - assert(_overflow_stack == 0, "Creating memory leak"); - _overflow_stack = - new (ResourceObj::C_HEAP) GrowableArray(10, true); -} - -void RegionTaskQueueWithOverflow::save(RegionTask t) { - if (TraceRegionTasksQueuing && Verbose) { - gclog_or_tty->print_cr("CTQ: save " PTR_FORMAT, t); - } - if(!_region_queue.push(t)) { - _overflow_stack->push(t); - } -} - -// Note that using this method will retrieve all regions -// that have been saved but that it will always check -// the overflow stack. It may be more efficient to -// check the stealable queue and the overflow stack -// separately. -bool RegionTaskQueueWithOverflow::retrieve(RegionTask& region_task) { - bool result = retrieve_from_overflow(region_task); - if (!result) { - result = retrieve_from_stealable_queue(region_task); - } - if (TraceRegionTasksQueuing && Verbose && result) { - gclog_or_tty->print_cr(" CTQ: retrieve " PTR_FORMAT, result); - } - return result; -} - -bool RegionTaskQueueWithOverflow::retrieve_from_stealable_queue( - RegionTask& region_task) { - bool result = _region_queue.pop_local(region_task); - if (TraceRegionTasksQueuing && Verbose) { - gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task); - } - return result; -} - -bool -RegionTaskQueueWithOverflow::retrieve_from_overflow(RegionTask& region_task) { - bool result; - if (!_overflow_stack->is_empty()) { - region_task = _overflow_stack->pop(); - result = true; - } else { - region_task = (RegionTask) NULL; - result = false; - } - if (TraceRegionTasksQueuing && Verbose) { - gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task); - } - return result; -} diff -r c4a3e3140f7b -r 88db80c8e49c hotspot/src/share/vm/utilities/taskqueue.hpp --- a/hotspot/src/share/vm/utilities/taskqueue.hpp Wed Jul 05 17:17:22 2017 +0200 +++ b/hotspot/src/share/vm/utilities/taskqueue.hpp Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,8 +109,9 @@ public: TaskQueueSuper() : _bottom(0), _age() {} - // Return true if the TaskQueue contains any tasks. - bool peek() { return _bottom != _age.top(); } + // Return true if the TaskQueue contains/does not contain any tasks. + bool peek() const { return _bottom != _age.top(); } + bool is_empty() const { return size() == 0; } // Return an estimate of the number of elements in the queue. // The "careful" version admits the possibility of pop_local/pop_global @@ -165,18 +166,16 @@ void initialize(); - // Push the task "t" on the queue. Returns "false" iff the queue is - // full. + // Push the task "t" on the queue. Returns "false" iff the queue is full. inline bool push(E t); - // If succeeds in claiming a task (from the 'local' end, that is, the - // most recently pushed task), returns "true" and sets "t" to that task. - // Otherwise, the queue is empty and returns false. + // Attempts to claim a task from the "local" end of the queue (the most + // recently pushed). If successful, returns true and sets t to the task; + // otherwise, returns false (the queue is empty). inline bool pop_local(E& t); - // If succeeds in claiming a task (from the 'global' end, that is, the - // least recently pushed task), returns "true" and sets "t" to that task. - // Otherwise, the queue is empty and returns false. + // Like pop_local(), but uses the "global" end of the queue (the least + // recently pushed). bool pop_global(E& t); // Delete any resource associated with the queue. @@ -198,7 +197,6 @@ template void GenericTaskQueue::initialize() { _elems = NEW_C_HEAP_ARRAY(E, N); - guarantee(_elems != NULL, "Allocation failed."); } template @@ -289,7 +287,87 @@ FREE_C_HEAP_ARRAY(E, _elems); } -// Inherits the typedef of "Task" from above. +// OverflowTaskQueue is a TaskQueue that also includes an overflow stack for +// elements that do not fit in the TaskQueue. +// +// Three methods from super classes are overridden: +// +// initialize() - initialize the super classes and create the overflow stack +// push() - push onto the task queue or, if that fails, onto the overflow stack +// is_empty() - return true if both the TaskQueue and overflow stack are empty +// +// Note that size() is not overridden--it returns the number of elements in the +// TaskQueue, and does not include the size of the overflow stack. This +// simplifies replacement of GenericTaskQueues with OverflowTaskQueues. +template +class OverflowTaskQueue: public GenericTaskQueue +{ +public: + typedef GrowableArray overflow_t; + typedef GenericTaskQueue taskqueue_t; + + OverflowTaskQueue(); + ~OverflowTaskQueue(); + void initialize(); + + inline overflow_t* overflow_stack() const { return _overflow_stack; } + + // Push task t onto the queue or onto the overflow stack. Return true. + inline bool push(E t); + + // Attempt to pop from the overflow stack; return true if anything was popped. + inline bool pop_overflow(E& t); + + inline bool taskqueue_empty() const { return taskqueue_t::is_empty(); } + inline bool overflow_empty() const { return overflow_stack()->is_empty(); } + inline bool is_empty() const { + return taskqueue_empty() && overflow_empty(); + } + +private: + overflow_t* _overflow_stack; +}; + +template +OverflowTaskQueue::OverflowTaskQueue() +{ + _overflow_stack = NULL; +} + +template +OverflowTaskQueue::~OverflowTaskQueue() +{ + if (_overflow_stack != NULL) { + delete _overflow_stack; + _overflow_stack = NULL; + } +} + +template +void OverflowTaskQueue::initialize() +{ + taskqueue_t::initialize(); + assert(_overflow_stack == NULL, "memory leak"); + _overflow_stack = new (ResourceObj::C_HEAP) GrowableArray(10, true); +} + +template +bool OverflowTaskQueue::push(E t) +{ + if (!taskqueue_t::push(t)) { + overflow_stack()->push(t); + } + return true; +} + +template +bool OverflowTaskQueue::pop_overflow(E& t) +{ + if (overflow_empty()) return false; + t = overflow_stack()->pop(); + return true; +} + class TaskQueueSetSuper: public CHeapObj { protected: static int randomParkAndMiller(int* seed0); @@ -323,11 +401,11 @@ T* queue(uint n); - // The thread with queue number "queue_num" (and whose random number seed - // is at "seed") is trying to steal a task from some other queue. (It - // may try several queues, according to some configuration parameter.) - // If some steal succeeds, returns "true" and sets "t" the stolen task, - // otherwise returns false. + // The thread with queue number "queue_num" (and whose random number seed is + // at "seed") is trying to steal a task from some other queue. (It may try + // several queues, according to some configuration parameter.) If some steal + // succeeds, returns "true" and sets "t" to the stolen task, otherwise returns + // false. bool steal(uint queue_num, int* seed, E& t); bool peek(); @@ -507,7 +585,7 @@ uint localBot = _bottom; // This value cannot be N-1. That can only occur as a result of // the assignment to bottom in this method. If it does, this method - // resets the size( to 0 before the next call (which is sequential, + // resets the size to 0 before the next call (which is sequential, // since this is pop_local.) uint dirty_n_elems = dirty_size(localBot, _age.top()); assert(dirty_n_elems != N - 1, "Shouldn't be possible..."); @@ -533,8 +611,7 @@ } } -typedef oop Task; -typedef GenericTaskQueue OopTaskQueue; +typedef GenericTaskQueue OopTaskQueue; typedef GenericTaskQueueSet OopTaskQueueSet; #ifdef _MSC_VER @@ -615,35 +692,8 @@ #pragma warning(pop) #endif -typedef GenericTaskQueue OopStarTaskQueue; +typedef OverflowTaskQueue OopStarTaskQueue; typedef GenericTaskQueueSet OopStarTaskQueueSet; -typedef size_t RegionTask; // index for region -typedef GenericTaskQueue RegionTaskQueue; -typedef GenericTaskQueueSet RegionTaskQueueSet; - -class RegionTaskQueueWithOverflow: public CHeapObj { - protected: - RegionTaskQueue _region_queue; - GrowableArray* _overflow_stack; - - public: - RegionTaskQueueWithOverflow() : _overflow_stack(NULL) {} - // Initialize both stealable queue and overflow - void initialize(); - // Save first to stealable queue and then to overflow - void save(RegionTask t); - // Retrieve first from overflow and then from stealable queue - bool retrieve(RegionTask& region_index); - // Retrieve from stealable queue - bool retrieve_from_stealable_queue(RegionTask& region_index); - // Retrieve from overflow - bool retrieve_from_overflow(RegionTask& region_index); - bool is_empty(); - bool stealable_is_empty(); - bool overflow_is_empty(); - uint stealable_size() { return _region_queue.size(); } - RegionTaskQueue* task_queue() { return &_region_queue; } -}; - -#define USE_RegionTaskQueueWithOverflow +typedef OverflowTaskQueue RegionTaskQueue; +typedef GenericTaskQueueSet RegionTaskQueueSet; diff -r c4a3e3140f7b -r 88db80c8e49c jaxp/.hgtags --- a/jaxp/.hgtags Wed Jul 05 17:17:22 2017 +0200 +++ b/jaxp/.hgtags Wed Jul 05 17:18:12 2017 +0200 @@ -75,3 +75,4 @@ d4adf4f2d14c7b79df0a81de884b6b57c6850802 jdk7-b98 7ef8469021fbc824ac49d57c83a14b1bb08f1766 jdk7-b99 d524be5ef62e8b8cb890c59a5d2c19ef0ab50d45 jdk7-b100 +17f62a566a2020fd908e77106ed885e0c4e7c14d jdk7-b101 diff -r c4a3e3140f7b -r 88db80c8e49c jaxp/jaxp.properties --- a/jaxp/jaxp.properties Wed Jul 05 17:17:22 2017 +0200 +++ b/jaxp/jaxp.properties Wed Jul 05 17:18:12 2017 +0200 @@ -28,7 +28,7 @@ jaxp_src.bundle.name=jdk7-jaxp-m7.zip jaxp_src.bundle.md5.checksum=22e95fbdb9fb7d8b6b6fc0a1d76d1fbd jaxp_src.master.bundle.dir=${drops.master.copy.base} -jaxp_src.master.bundle.url.base=https://jaxp.dev.java.net/files/documents/913/147490 +jaxp_src.master.bundle.url.base=https://jaxp.dev.java.net/files/documents/913/150785 #jaxp_tests.bundle.name=jdk7-jaxp-tests-2009_08_28.zip #jaxp_tests.master.bundle.dir=${drops.master.copy.base} diff -r c4a3e3140f7b -r 88db80c8e49c jaxws/.hgtags --- a/jaxws/.hgtags Wed Jul 05 17:17:22 2017 +0200 +++ b/jaxws/.hgtags Wed Jul 05 17:18:12 2017 +0200 @@ -75,3 +75,4 @@ 4571098071094e705e680db5324bfa15a57b1290 jdk7-b98 818366ce23d8919cafaa4db4c51605ee2a7c8eaf jdk7-b99 bd26d0ce0c3cb43e58a8e2770cc03f26d96ffe5c jdk7-b100 +b55ce274490082712f5e002b38d2eed505ca863d jdk7-b101 diff -r c4a3e3140f7b -r 88db80c8e49c jdk/.hgtags --- a/jdk/.hgtags Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/.hgtags Wed Jul 05 17:18:12 2017 +0200 @@ -75,3 +75,4 @@ 82593186fa54ab12f17af31f86a7bf364efaf4df jdk7-b98 2587c9f0b60dc3146b4247b8674ada456a643d6f jdk7-b99 820b4e843d5168370a3bf166d19751a3271d8575 jdk7-b100 +d58354a69011f3d3354765fa3167567c4c4a9612 jdk7-b101 diff -r c4a3e3140f7b -r 88db80c8e49c jdk/make/common/Release.gmk diff -r c4a3e3140f7b -r 88db80c8e49c jdk/make/common/shared/Defs-javadoc.gmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/common/shared/Defs-javadoc.gmk Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,93 @@ +# +# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# + +# Copyright year for beginning of Java and some of the apis +# (Needed when creating the javadocs) +FIRST_COPYRIGHT_YEAR = 1993 +DOMAPI_FIRST_COPYRIGHT_YEAR = 2005 +MIRROR_FIRST_COPYRIGHT_YEAR = 2004 +DOCLETAPI_FIRST_COPYRIGHT_YEAR = 1993 +TAGLETAPI_FIRST_COPYRIGHT_YEAR = 1993 +JDI_FIRST_COPYRIGHT_YEAR = 1999 +JAAS_FIRST_COPYRIGHT_YEAR = 1998 +JGSS_FIRST_COPYRIGHT_YEAR = 2000 +SMARTCARDIO_FIRST_COPYRIGHT_YEAR = 2005 +HTTPSERVER_FIRST_COPYRIGHT_YEAR = 2005 +MGMT_FIRST_COPYRIGHT_YEAR = 2003 +ATTACH_FIRST_COPYRIGHT_YEAR = 2005 +JCONSOLE_FIRST_COPYRIGHT_YEAR = 2006 +SCTPAPI_FIRST_COPYRIGHT_YEAR = 2009 +TRACING_FIRST_COPYRIGHT_YEAR = 2008 +TREEAPI_FIRST_COPYRIGHT_YEAR = 2005 +JNLP_FIRST_COPYRIGHT_YEAR = 1998 +PLUGIN2_FIRST_COPYRIGHT_YEAR = 2007 + +# Oracle name +COMPANY_NAME = Oracle and/or its affiliates + +# Copyright address +COMPANY_ADDRESS = 500 Oracle Parkway
Redwood Shores, CA 94065 USA. + +# The trademark symbol +TRADEMARK = ™ + +# Common copyright lines used +# The word "Copyright" might optionally be a link to the file cpyr.html. +# The first year of copyright may vary or not be available. +# The address to the company might be optional. +COMMA:= , +EMPTY:= +SPACE:=$(EMPTY) $(EMPTY) +COPYRIGHT_SYMBOL = &\#x00a9; +# Macros to handle the optional empty args. +# (The GNU make 3.78.1 "if" conditional is broken, fixed in GNU make 3.81) +define OptionalCopyrightUrl # url +$(shell \ + if [ "$1" != "" ] ; then \ + printf "Copyright" "$1"; \ + else \ + printf "Copyright"; \ + fi) +endef +define OptionalCopyrightFirstYear # year +$(shell \ + if [ "$1" != "" ] ; then \ + printf "%s," "$1";\ + fi) +endef +define OptionalCompanyAddress # address +$(shell \ + if [ "$1" != "" ] ; then \ + printf "%s" "$1";\ + fi) +endef +define CopyrightLine # optionalurl optionalfirstyear optionaladdress +$(call OptionalCopyrightUrl,$1) $(COPYRIGHT_SYMBOL)\ +$(call OptionalCopyrightFirstYear,$2) $(COPYRIGHT_YEAR),\ +$(COMPANY_NAME).\ +$(call OptionalCompanyAddress,$3)\ +All rights reserved. +endef + diff -r c4a3e3140f7b -r 88db80c8e49c jdk/make/common/shared/Defs-windows.gmk --- a/jdk/make/common/shared/Defs-windows.gmk Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/make/common/shared/Defs-windows.gmk Wed Jul 05 17:18:12 2017 +0200 @@ -230,7 +230,8 @@ # Compilers, SDK, and Visual Studio (MSDEV) [32bit is different from 64bit] ifeq ($(ARCH_DATA_MODEL), 32) - # Try looking in MSVCDIR or MSVCDir area first (set by vcvars32.bat) + # Try looking in MSVCDIR or MSVCDir area first + # (set by vcvars32.bat for VC .NET, not defined in the VC 2008/2010) ifdef MSVCDIR xMSVCDIR :="$(subst \,/,$(MSVCDIR))" _msvc_dir :=$(call FullPath,$(xMSVCDIR)) @@ -238,11 +239,6 @@ ifdef MSVCDir xMSVCDIR :="$(subst \,/,$(MSVCDir))" _msvc_dir :=$(call FullPath,$(xMSVCDIR)) - else - ifneq ($(_program_files),) - xMSVCDIR :="$(_program_files)/Microsoft Visual Studio .NET 2003/Vc7" - _msvc_dir :=$(call FullPath,$(xMSVCDIR)) - endif endif endif # If we still don't have it, look for VSnnCOMNTOOLS (newest first), diff -r c4a3e3140f7b -r 88db80c8e49c jdk/make/docs/Makefile --- a/jdk/make/docs/Makefile Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/make/docs/Makefile Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,4 @@ -# -# Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -30,6 +29,41 @@ PRODUCT=docs include $(BUILDDIR)/common/Defs.gmk +# Get CopyrightLine macro and other shared variables +include $(BUILDDIR)/common/shared/Defs-javadoc.gmk + +# Url to root of documents +DOCSDIR_URL = {@docroot}/$(GET2DOCSDIR) + +# Url to copyright html file +COPYRIGHT_URL-7 = $(DOCSDIR_URL)/legal/cpyr.html +COPYRIGHT_URL = $(COPYRIGHT_URL-$(JDK_MINOR_VERSION)) + +# Url to bug filing site +BUG_SUBMIT_URL = http://bugs.sun.com/services/bugreport/index.jsp + +# Common line for how to submit a bug or rfe +BUG_SUBMIT_LINE = Submit a bug or feature + +# Url to devdocs page +# Was: http://java.sun.com/javase/6/webnotes/devdocs-vs-specs.html +DEV_DOCS_URL-5 = http://java.sun.com/j2se/1.5.0/docs +DEV_DOCS_URL-6 = http://download.oracle.com/docs/cd/E17409_01/javase/6/docs +DEV_DOCS_URL-7 = http://download.oracle.com/docs/cd/E17409_01/javase/7/docs +DEV_DOCS_URL = $(DEV_DOCS_URL-$(JDK_MINOR_VERSION)) + +# Url to Java Language Spec +JLS3_URL = http://java.sun.com/docs/books/jls/ + +# Common Java trademark line +JAVA_TRADEMARK_LINE = Java is a trademark or registered trademark of \ +$(COMPANY_NAME) in the US and other countries. + +# +# Definitions for imported components +# +include $(BUILDDIR)/common/internal/ImportComponents.gmk + # We override whatever the max VM memory setting is here. # NOTE: javadoc will not complete without these larger settings. # WARNING: This could cause thrashing on low memory machines. @@ -39,418 +73,155 @@ MAX_VM_MEMORY = 512 endif -# -# Variables used by docs target +# List of all possible directories for javadoc to look for sources +# NOTE: Quotes are required around sourcepath argument only on Windows. +# Otherwise, you get "No packages or classes specified." due +# to $(CLASSPATH_SEPARATOR) being interpreted as an end of +# command (newline or shell ; character) +ALL_SOURCE_DIRS = $(SHARE_SRC)/classes \ + $(IMPORTSRCDIR) \ + $(GENSRCDIR) \ + $(SHARE_SRC)/../solaris/classes \ + $(SHARE_SRC)/../windows/classes \ + $(SHARE_SRC)/doc/stub +EMPTY:= +SPACE:= $(EMPTY) $(EMPTY) +RELEASEDOCS_SOURCEPATH = \ + $(subst $(SPACE),$(CLASSPATH_SEPARATOR),$(strip $(ALL_SOURCE_DIRS))) + +# Prep for javadoc creation, assumes $@ is an index.html file +define prep-javadoc +@if [ -f "$@" -a "$?" != "" ] ; then \ + $(ECHO) "# Dependencies have changed: $?"; \ +fi +$(RM) -r $(@D) +$(MKDIR) -p $(@D) +endef + +# A cache of the directories in ALL_SOURCE_DIRS +DIRECTORY_CACHE = $(DOCSTMPDIR)/directory.cache + +# Given a list of packages, return a list of files or dirs to be dependent on +# (Currently only returning a list of directories) +define PackageDependencies # packages +$(shell \ + if [ "$1" != "" -a -f $(DIRECTORY_CACHE) ] ; then \ + for p in $1 ; do \ + pd=`$(ECHO) $${p} | $(SED) -e 's@[.]@/@g'`; \ + $(CAT) $(DIRECTORY_CACHE) | $(GREP) "/$${pd}/" ; \ + done; \ + fi \ +) +endef + +# Given a list of packages, add packages that exist to $@, print summary +define PackageFilter # packages +@if [ "$1" != "" ] ; then \ + for p in $1 ; do \ + pd=`$(ECHO) $${p} | $(SED) -e 's@[.]@/@g'`; \ + found="false"; \ + for cp in $(ALL_SOURCE_DIRS) ; do \ + if [ -d $${cp}/$${pd} ] ; then \ + $(ECHO) "$${p}" >> $@; \ + found="true"; \ + break; \ + fi; \ + done; \ + if [ "$${found}" = "false" ] ; then \ + $(ECHO) "WARNING: Package not found: $${p}"; \ + fi; \ + done; \ +fi +endef + +# Print out a summary of the javadoc command about to be run +define JavadocSummary # optionsfile packagesfile +@$(ECHO) "# Summary for $@";\ + $(ECHO) "# Options (`$(BASENAME) $1`):"; $(SED) -e 's@^@# @' $1; \ + $(ECHO) "# Packages (`$(BASENAME) $2`):";$(SED) -e 's@^@# @' $2 +endef + # -DOCSTMPDIR = $(TEMPDIR)/doctmp +# Temporary directory for javadoc creation +# +DOCSTMPDIR = $(TEMPDIR)/doctmp + +# +# Different api directories created from root directory +# +COREAPI_DOCSDIR = $(DOCSDIR)/api +JDK_API_DOCSDIR = $(DOCSDIR)/jdk/api +JRE_API_DOCSDIR = $(DOCSDIR)/jre/api +PLATFORM_DOCSDIR = $(DOCSDIR)/platform + +# The non-core api javadocs need to be able to access the root of the core +# api directory, so for jdk/api or jre/api to get to the core api/ +# directory we would use this: +JDKJRE2COREAPI = ../../api + +# Common bottom argument +define CommonBottom # year +

$(call CopyrightLine,,$1,) +endef +# Common trademark bottom argument (Not sure why this is used sometimes) +define CommonTrademarkBottom # year +\ +$(BUG_SUBMIT_LINE)
$(JAVA_TRADEMARK_LINE)
\ +$(call CopyrightLine,,$1,$(COMPANY_ADDRESS))\ +
+endef + +# Core api bottom argument (with special sauce) +COREAPI_BOTTOM = $(BUG_SUBMIT_LINE)\ +
For further API reference and developer documentation, \ +see Java SE Documentation. \ +That documentation contains more detailed, developer-targeted descriptions, \ +with conceptual overviews, definitions of terms, workarounds, \ +and working code examples.

\ +$(call CopyrightLine,$(COPYRIGHT_URL),$(FIRST_COPYRIGHT_YEAR),)\ + + +# Common javadoc options used by all COMMON_JAVADOCFLAGS = \ - $(NO_PROPRIETARY_API_WARNINGS) \ + $(NO_PROPRIETARY_API_WARNINGS) \ -source 1.5 \ -quiet \ -use \ -keywords \ - $(JAVADOC_VM_MEMORY_FLAGS) \ $(ADDITIONAL_JAVADOCFLAGS) ADDITIONAL_JAVADOCFLAGS = -CORE_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - $(TAGS) \ - -encoding ISO-8859-1 \ - -splitIndex \ - -doctitle $(DOCTITLE_SWITCH) \ - -windowtitle $(WINDOWTITLE_SWITCH) \ - -header $(HEADER_SWITCH) \ - $(TOPOPTION) \ - -bottom $(JAVADOCBOTTOM_SWITCH) \ - $(OVERVIEW_OPTION) - -DRAFT = '
DRAFT '$(MILESTONE)-$(BUILD_NUMBER)'' -THIS_YEAR := $(shell $(DATE) | $(SED) -e 's/ / /g' | $(CUT) -d' ' -f6) -TRADEMARK = &\#x2122; - -IGNORED_TAGS = beaninfo revised since.unbundled spec specdefault Note ToDo - -JLS3_URL = http://java.sun.com/docs/books/jls/ -JLS3_CITE = \ - The Java Language Specification, Third Edition -TAG_JLS3 = -tag 'jls3:a:See $(JLS3_CITE):' - -TAGS = $(IGNORED_TAGS:%=-tag %:X) $(TAG_JLS3) - -ifeq ($(MILESTONE), fcs) - DOCTITLE_SWITCH = $(JAVADOCTITLE) - WINDOWTITLE_SWITCH = $(JAVADOCWINDOWTITLE) - HEADER_SWITCH = $(JAVADOCHEADER) - TOPOPTION= - JAVADOCBOTTOM_SWITCH= $(JAVADOCBOTTOM) - OVERVIEW_OPTION = -overview $(JAVADOCOVERVIEW) -else - DOCTITLE_SWITCH = $(JAVADOCTITLE_EARLYACCESS)$(DRAFT) - WINDOWTITLE_SWITCH = $(JAVADOCWINDOWTITLE)" $(BUILD_NUMBER)" - HEADER_SWITCH = $(JAVADOCHEADER)$(DRAFT) - JAVADOCBOTTOM_SWITCH= $(JAVADOCBOTTOM_EARLYACCESS) - TOPOPTION= -top $(JAVADOCTOP_EARLYACCESS) - OVERVIEW_OPTION = +# Draft used for non-fcs documents +JDK_IS_FCS = false +DRAFT_HEADER = +ifeq ($(JDK_MINOR_VERSION),5) + JDK_IS_FCS = true +endif +ifeq ($(JDK_MINOR_VERSION),6) + JDK_IS_FCS = true +endif +ifeq ($(JDK_IS_FCS),false) + ifneq ($(MILESTONE), fcs) + DRAFT_HEADER =
DRAFT $(MILESTONE)-$(BUILD_NUMBER) + DRAFT_BOTTOM =
DRAFT $(MILESTONE)-$(BUILD_NUMBER) + DRAFT_WINTITLE = $(BUILD_NUMBER) + # Early access top text (not used in FCS releases) + COREAPI_TOP_EARLYACCESS = \ +

\ +
\ +Please note that the specifications and other information \ +contained herein are not final and are subject to change. \ +The information is being made available to you solely for purpose of \ +evaluation. \ +
+ endif endif -JAVADOCTITLE = 'Java$(TRADEMARK) Platform, Standard Edition $(JDK_MINOR_VERSION)
API Specification' -JAVADOCWINDOWTITLE = 'Java Platform SE $(JDK_MINOR_VERSION)' -JAVADOCHEADER = 'Java$(TRADEMARK) Platform
Standard Ed. $(JDK_MINOR_VERSION)
' -JAVADOCBOTTOM = 'Submit a bug or feature
For further API reference and developer documentation, see Java SE Developer Documentation. That documentation contains more detailed, developer-targeted descriptions, with conceptual overviews, definitions of terms, workarounds, and working code examples.

Copyright $(THIS_YEAR) Sun Microsystems, Inc. All Rights Reserved. Use is subject to license terms. Also see the documentation redistribution policy.' -JAVADOCOVERVIEW = $(SHARE_SRC)/classes/overview-core.html - -# -# Early access top and bottom text (for snapshots, beta and rc) -# -JAVADOCTOP_EARLYACCESS = '

Please note that this documentation is not final and is subject to change.
' -JAVADOCBOTTOM_EARLYACCESS = 'Submit a bug or feature

Copyright $(THIS_YEAR) Sun Microsystems, Inc. All Rights Reserved. Use is subject to license terms.' -JAVADOCTITLE_EARLYACCESS = $(subst Specification,Documentation,$(JAVADOCTITLE)) - -# -# Variables used by domapidocs target -# - -DOMAPI_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -splitIndex \ - -doctitle $(DOMAPI_JAVADOCTITLE) \ - -windowtitle $(DOMAPI_JAVADOCWINDOWTITLE) \ - -header $(DOMAPI_JAVADOCHEADER) \ - -bottom $(DOMAPI_JAVADOCBOTTOM) \ - -group $(DOMAPI_GROUPNAME) $(DOMAPI_REGEXP) -DOMAPI_JAVADOCTITLE = 'Common DOM API' -DOMAPI_JAVADOCWINDOWTITLE = 'Common DOM API' -DOMAPI_JAVADOCHEADER = 'Common DOM API' -DOMAPI_JAVADOCBOTTOM = 'Submit a bug or feature
Java is a trademark or registered trademark of Sun Microsystems, Inc. in the US and other countries.
Copyright $(THIS_YEAR) Sun Microsystems, Inc. 4150 Network Circle
Santa Clara, California, 95054, U.S.A. All Rights Reserved.
' -DOMAPI_GROUPNAME = "Packages" -DOMAPI_REGEXP = "com.sun.java.browser.dom:org.w3c.dom*" -# DOMAPI_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by mirrordocs target -# - -MIRROR_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -doctitle $(MIRROR_JAVADOCTITLE) \ - -windowtitle $(MIRROR_JAVADOCWINDOWTITLE) \ - -header $(MIRROR_JAVADOCHEADER) \ - -bottom $(MIRROR_JAVADOCBOTTOM) \ - -group $(MIRROR_GROUPNAME) $(MIRROR_REGEXP) \ - -overview $(MIRROR_OVERVIEW) -MIRROR_JAVADOCTITLE = 'Mirror API' -MIRROR_JAVADOCWINDOWTITLE = 'Mirror API' -MIRROR_JAVADOCHEADER = 'Mirror API' -MIRROR_JAVADOCBOTTOM = 'Report a bug or request a feature.
Copyright $(THIS_YEAR) Sun Microsystems, Inc. All Rights Reserved. Use is subject to license terms.
' -MIRROR_GROUPNAME = "Packages" -MIRROR_OVERVIEW = $(IMPORTSRCDIR)/com/sun/mirror/overview.html -MIRROR_REGEXP = "com.sun.mirror.*" -MIRROR_DESTDIR = $(DOCSDIR)/jdk/api/apt/mirror -MIRROR_LINKOPT = -linkoffline ../../../../api $(DOCSDIR)/api/ -# MIRROR_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by docletapidocs target -# - -DOCLETAPI_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -breakiterator \ - -encoding ascii \ - -doctitle $(DOCLETAPI_JAVADOCTITLE) \ - -windowtitle $(DOCLETAPI_JAVADOCWINDOWTITLE) \ - -header $(DOCLETAPI_JAVADOCHEADER) \ - -bottom $(DOCLETAPI_JAVADOCBOTTOM) \ - -group $(DOCLETAPI_GROUPNAME) $(DOCLETAPI_REGEXP) -DOCLETAPI_JAVADOCTITLE = 'Doclet API' -DOCLETAPI_JAVADOCWINDOWTITLE = 'Doclet API' -DOCLETAPI_JAVADOCHEADER = 'Doclet API' -DOCLETAPI_JAVADOCBOTTOM = 'Submit a bug or feature
Java is a trademark or registered trademark of Sun Microsystems, Inc. in the US and other countries.
Copyright 1993-$(THIS_YEAR) Sun Microsystems, Inc. 4150 Network Circle
Santa Clara, California, 95054, U.S.A. All Rights Reserved.
' -DOCLETAPI_GROUPNAME = "Packages" -DOCLETAPI_REGEXP = "com.sun.javadoc" -DOCLETAPI_LINKOPT = -linkoffline ../../../../api $(DOCSDIR)/api/ -# DOCLETAPI_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by tagletapidocs target -# - -TAGLETAPI_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nonavbar \ - -noindex \ - -bottom $(TAGLETAPI_JAVADOCBOTTOM) -TAGLETAPI_JAVADOCBOTTOM = 'Submit a bug or feature
Java is a trademark or registered trademark of Sun Microsystems, Inc. in the US and other countries.
Copyright 1993-$(THIS_YEAR) Sun Microsystems, Inc. 4150 Network Circle
Santa Clara, California, 95054, U.S.A. All Rights Reserved.
' -# TAGLETAPI_FILE is located in NON_CORE_PKGS.gmk - -# -# Variables used by jdi target -# - -JPDA_SOURCEPATH = $(TOPDIR)/src/share/classes - -JDI_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(DOCSDIR)/jdk/api/jpda/jdi \ - -sourcepath $(JPDA_SOURCEPATH) \ - -windowtitle $(JDI_WINDOWTITLE) \ - -doctitle $(JDI_DOCTITLE) \ - -header $(JDI_HEADER) \ - -linkoffline ../../../../api $(DOCSDIR)/api/ \ - -overview $(JPDA_SOURCEPATH)/jdi-overview.html -JDI_WINDOWTITLE = "Java Debug Interface" -JDI_DOCTITLE = "Java$(TRADEMARK) Debug Interface" -JDI_HEADER = "Java Debug Interface" -# JDI_PKGS is located in NON_CORE_PKGS.gmk - -# Variables used by security components -SECURITYAPI_JAVADOCBOTTOM = 'Report a bug or request a feature.
Copyright $(THIS_YEAR) Sun Microsystems, Inc. All Rights Reserved. Use is subject to license terms.
' - -# -# Variables used by JAAS target -# -# NOTE: Quotes are required around sourcepath argument only on Windows. Otherwise, -# you get "No packages or classes specified." due to $(CLASSPATH_SEPARATOR) -# being interpreted as an end of command (newline) - -JAAS_SOURCEPATH = "$(TOPDIR)/src/share/classes$(CLASSPATH_SEPARATOR)$(TOPDIR)/src/solaris/classes$(CLASSPATH_SEPARATOR)$(TOPDIR)/src/windows/classes$(CLASSPATH_SEPARATOR)$(TOPDIR)/src/linux/classes" -JAAS_DOCDIR = $(DOCSDIR)/jre/api/security/jaas/spec -JAAS_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(JAAS_DOCDIR) \ - -sourcepath $(JAAS_SOURCEPATH) \ - -windowtitle $(JAAS_WINDOWTITLE) \ - -doctitle $(JAAS_DOCTITLE) \ - -header $(JAAS_JAVADOCHEADER) \ - -bottom $(SECURITYAPI_JAVADOCBOTTOM) \ - -linkoffline ../../../../../api $(DOCSDIR)/api/ \ - -overview $(TOPDIR)/src/share/classes/com/sun/security/auth/jaas-overview.html -JAAS_WINDOWTITLE = "Java Authentication and Authorization Service " -JAAS_DOCTITLE = "Java$(TRADEMARK) Authentication and Authorization Service" -JAAS_JAVADOCHEADER = "JAAS" -# JAAS_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by JGSS target -# - -JGSS_SOURCEPATH = $(TOPDIR)/src/share/classes -JGSS_DOCDIR = $(DOCSDIR)/jre/api/security/jgss/spec - -JGSS_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(JGSS_DOCDIR) \ - -sourcepath $(JGSS_SOURCEPATH) \ - -windowtitle $(JGSS_WINDOWTITLE) \ - -doctitle $(JGSS_DOCTITLE) \ - -header $(JGSS_JAVADOCHEADER) \ - -bottom $(SECURITYAPI_JAVADOCBOTTOM) \ - -linkoffline ../../../../../api $(DOCSDIR)/api/ \ - -overview $(JGSS_SOURCEPATH)/com/sun/security/jgss/jgss-overview.html - -JGSS_WINDOWTITLE = "Java GSS-API Utilities " -JGSS_DOCTITLE = "Java$(TRADEMARK) GSS-API Utilities" -JGSS_JAVADOCHEADER = "Java GSS-API Utilities" -# JGSS_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by SMARTCARDIO target -# - -SMARTCARDIO_SOURCEPATH = $(TOPDIR)/src/share/classes -SMARTCARDIO_DOCDIR = $(DOCSDIR)/jre/api/security/smartcardio/spec - -SMARTCARDIO_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(SMARTCARDIO_DOCDIR) \ - -sourcepath $(SMARTCARDIO_SOURCEPATH) \ - -windowtitle $(SMARTCARDIO_WINDOWTITLE) \ - -doctitle $(SMARTCARDIO_DOCTITLE) \ - -header $(SMARTCARDIO_JAVADOCHEADER) \ - -bottom $(SECURITYAPI_JAVADOCBOTTOM) \ - -linkoffline ../../../../../api $(DOCSDIR)/api/ - -SMARTCARDIO_WINDOWTITLE = "Java Smart Card I/O" -SMARTCARDIO_DOCTITLE = "Java$(TRADEMARK) Smart Card I/O" -SMARTCARDIO_JAVADOCHEADER = "Java Smart Card I/O" -# SMARTCARDIO_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by TRACING target -# - -TRACING_SOURCEPATH = $(TOPDIR)/src/share/classes -TRACING_DOCDIR = $(DOCSDIR)/jre/api/tracing - -TRACING_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(TRACING_DOCDIR) \ - -sourcepath $(TRACING_SOURCEPATH) \ - -windowtitle $(TRACING_WINDOWTITLE) \ - -doctitle $(TRACING_DOCTITLE) \ - -header $(TRACING_JAVADOCHEADER) \ - -linkoffline ../../../../../api $(DOCSDIR)/api/ - -TRACING_WINDOWTITLE = "Tracing" -TRACING_DOCTITLE = "Java$(TRADEMARK) Platform Tracing" -TRACING_JAVADOCHEADER = "Platform Tracing" -# TRACING_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by HTTPSERVER target -# - -HTTPSERVER_SOURCEPATH = $(TOPDIR)/src/share/classes -HTTPSERVER_DOCDIR = $(DOCSDIR)/jre/api/net/httpserver/spec - -HTTPSERVER_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(HTTPSERVER_DOCDIR) \ - -sourcepath $(HTTPSERVER_SOURCEPATH) \ - -windowtitle $(HTTPSERVER_WINDOWTITLE) \ - -doctitle $(HTTPSERVER_DOCTITLE) \ - -header $(HTTPSERVER_JAVADOCHEADER) \ - -linkoffline ../../../../../api $(DOCSDIR)/api/ - -HTTPSERVER_WINDOWTITLE = "Java HTTP Server" -HTTPSERVER_DOCTITLE = "Java$(TRADEMARK) HTTP Server" -HTTPSERVER_JAVADOCHEADER = "Java HTTP Server" -# HTTPSERVER_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by sctp target -# - -SCTPAPI_SOURCEPATH = $(TOPDIR)/src/share/classes -SCTPAPI_DOCDIR = $(DOCSDIR)/jre/api/nio/sctp/spec - -SCTPAPI_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(SCTPAPI_DOCDIR) \ - -sourcepath $(SCTPAPI_SOURCEPATH) \ - -windowtitle $(SCTPAPI_WINDOWTITLE) \ - -doctitle $(SCTPAPI_DOCTITLE) \ - -header $(SCTPAPI_JAVADOCHEADER) \ - -bottom $(SCTPAPI_JAVADOCBOTTOM) \ - -linkoffline ../../../../../api $(DOCSDIR)/api/ - -SCTPAPI_WINDOWTITLE = "SCTP API" -SCTPAPI_DOCTITLE = "SCTP API" -SCTPAPI_JAVADOCHEADER = "SCTP API" -SCTPAPI_JAVADOCBOTTOM = 'Report a bug or request a feature.
Copyright $(THIS_YEAR) Sun Microsystems, Inc. All Rights Reserved. Use is subject to license terms.
' -# SCTPAPI_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by jvmti target -# -JVMTI_DOCS_SUBDIR = platform/jvmti -JVMTI_HTML = $(HOTSPOT_DOCS_IMPORT_PATH)/$(JVMTI_DOCS_SUBDIR)/jvmti.html - -# -# Variables used by mgmt target -# -MGMT_DOCDIR = $(DOCSDIR)/jre/api/management/ -MGMT_EXT_DIR = $(MGMT_DOCDIR)/extension -MGMT_SOURCEPATH = $(TOPDIR)/src/share/classes -JVM_MIB_NAME = JVM-MANAGEMENT-MIB.mib -JVM_MIB_SRC = $(CLOSED_SRC)/share/classes/sun/management/snmp/$(JVM_MIB_NAME) - -ifdef OPENJDK - COPY-MIB-TARGET = -else - COPY-MIB-TARGET = copy-mib -endif -MGMT_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(MGMT_EXT_DIR) \ - -sourcepath $(MGMT_SOURCEPATH) \ - -windowtitle $(MGMT_WINDOWTITLE) \ - -doctitle $(MGMT_DOCTITLE) \ - -header $(MGMT_HEADER) \ - -linkoffline ../../../../api $(DOCSDIR)/api/ \ - -overview $(MGMT_SOURCEPATH)/com/sun/management/mgmt-overview.html -MGMT_WINDOWTITLE = "Monitoring and Management Interface for the Java Platform" -MGMT_DOCTITLE = "Monitoring and Management Interface for the Java$(TRADEMARK) Platform" -MGMT_HEADER = "Monitoring and Management Interface for the Java Platform" -# MGMT_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by attach target -# - -ATTACH_SOURCEPATH = $(TOPDIR)/src/share/classes -ATTACH_DOCDIR = $(DOCSDIR)/jdk/api/attach/spec -ATTACH_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(ATTACH_DOCDIR) \ - -sourcepath $(ATTACH_SOURCEPATH) \ - -windowtitle $(ATTACH_WINDOWTITLE) \ - -doctitle $(ATTACH_DOCTITLE) \ - -header $(ATTACH_HEADER) \ - -linkoffline ../../../../api $(DOCSDIR)/api/ -ATTACH_WINDOWTITLE = "Attach API" -ATTACH_DOCTITLE = "Attach API" -ATTACH_HEADER = "Attach API" -# ATTACH_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by jconsole target -# - -JCONSOLE_SOURCEPATH = $(TOPDIR)/src/share/classes -JCONSOLE_DOCDIR = $(DOCSDIR)/jdk/api/jconsole/spec -JCONSOLE_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -nodeprecatedlist \ - -d $(JCONSOLE_DOCDIR) \ - -sourcepath $(JCONSOLE_SOURCEPATH) \ - -windowtitle $(JCONSOLE_WINDOWTITLE) \ - -doctitle $(JCONSOLE_DOCTITLE) \ - -header $(JCONSOLE_HEADER) \ - -linkoffline ../../../../api $(DOCSDIR)/api/ -JCONSOLE_WINDOWTITLE = "JConsole API" -JCONSOLE_DOCTITLE = "JConsole API" -JCONSOLE_HEADER = "JConsole API" -# JCONSOLE_PKGS is located in NON_CORE_PKGS.gmk - -# -# Variables used by treeapidocs target -# - -TREEAPI_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ - -encoding ascii \ - -doctitle $(TREEAPI_JAVADOCTITLE) \ - -windowtitle $(TREEAPI_JAVADOCWINDOWTITLE) \ - -header $(TREEAPI_JAVADOCHEADER) \ - -bottom $(TREEAPI_JAVADOCBOTTOM) \ - -group $(TREEAPI_GROUPNAME) $(TREEAPI_REGEXP) -# -# -overview $(TREEAPI_OVERVIEW) -# -TREEAPI_JAVADOCTITLE = 'Compiler Tree API' -TREEAPI_JAVADOCWINDOWTITLE = 'Compiler Tree API' -TREEAPI_JAVADOCHEADER = 'Compiler Tree API' -TREEAPI_JAVADOCBOTTOM = 'Report a bug or request a feature.
Copyright $(THIS_YEAR) Sun Microsystems, Inc. All Rights Reserved. Use is subject to license terms.
' -TREEAPI_GROUPNAME = "Packages" -TREEAPI_OVERVIEW = $(SHARE_SRC)/classes/com/sun/source/overview.html -TREEAPI_REGEXP = "com.sun.source.*" -TREEAPI_DESTDIR = $(DOCSDIR)/jdk/api/javac/tree -TREEAPI_LINKOPT = -linkoffline ../../../../api $(DOCSDIR)/api/ -# TREEAPI_PKGS is located in NON_CORE_PKGS.gmk - -# -# Path where javadoc should find source files for release docs -# -RELEASEDOCS_SRCPATH = "$(SHARE_SRC)/classes$(CLASSPATH_SEPARATOR)$(PLATFORM_SRC)/classes$(CLASSPATH_SEPARATOR)$(GENSRCDIR)$(CLASSPATH_SEPARATOR)$(SHARE_SRC)/doc/stub$(CLASSPATH_SEPARATOR)$(CLOSED_SRC)/share/classes$(CLASSPATH_SEPARATOR)$(IMPORTSRCDIR)" +################################################################# # # CORE_PKGS environment variable has been moved to the following file @@ -463,30 +234,13 @@ # include NON_CORE_PKGS.gmk -# Targets for all APIs other than the core platform APIs -ALL_OTHER_TARGETS = \ - mirrordocs \ - docletapidocs \ - tagletapidocs \ - domapidocs \ - jpdadocs \ - jaasdocs \ - jgssdocs \ - smartcardiodocs \ - tracingdocs \ - httpserverdocs \ - sctpdocs \ - mgmtdocs \ - attachdocs \ - jconsoledocs \ - treeapidocs +################################################################# -.PHONY: all docs -all docs: coredocs otherdocs +# +# Default target is same as docs target, create core api and all others it can +# -.PHONY: otherdocs -otherdocs: ${ALL_OTHER_TARGETS} - +all docs: coredocs otherdocs ################################################################# # Production Targets -- USE THESE TARGETS WHEN: @@ -496,9 +250,9 @@ # the downloaded doc bundle. # # See: Notes.html#releaseTargets -# Note: Spaces preceed ifdef/ifndef indents. Tabs preceed target commands (!) +# Note: Spaces precede ifdef/ifndef indents. Tabs precede target commands (!) # -.PHONY: sanitycheckcoredocs + sanitycheckcoredocs: @$(ECHO) "" @$(ECHO) "Building core api docs with these values:" @@ -512,199 +266,942 @@ exit 1 endif -# Maximize performance and ensure that build number & milestone are set. -.PHONY: rel-coredocs -rel-coredocs: sanitycheckcoredocs - @# ######## release version of core packages ######## - $(MAKE) coredocs +############################################################# +# +# coredocs +# +COREAPI_DOCTITLE = Java$(TRADEMARK) Platform, Standard Edition \ +$(JDK_MINOR_VERSION)
API Specification +COREAPI_WINDOWTITLE = Java Platform SE $(JDK_MINOR_VERSION) +COREAPI_HEADER = \ +Java$(TRADEMARK) Platform
Standard Ed. $(JDK_MINOR_VERSION)
+ +# Ignored tags +IGNORED_TAGS = beaninfo revised since.unbundled spec specdefault Note ToDo + +# Java language specification cite +JLS3_CITE = \ + The Java Language Specification, Third Edition +TAG_JLS3 = -tag 'jls3:a:See $(JLS3_CITE):' + +TAGS = $(IGNORED_TAGS:%=-tag %:X) $(TAG_JLS3) + +# Overview file for core apis +COREAPI_OVERVIEW = $(SHARE_SRC)/classes/overview-core.html + +# The index.html, options, and packages files +COREAPI_INDEX_FILE = $(COREAPI_DOCSDIR)/index.html +COREAPI_OPTIONS_FILE = $(DOCSTMPDIR)/coredocs.options +COREAPI_PACKAGES_FILE = $(DOCSTMPDIR)/coredocs.packages + +coredocs: $(COREAPI_INDEX_FILE) + +# Set relative location to core api document root +$(COREAPI_INDEX_FILE): GET2DOCSDIR=.. -.PHONY: rel-docs -rel-docs: rel-coredocs ${ALL_OTHER_TARGETS} +# Run javadoc if the index file is out of date or missing +$(COREAPI_INDEX_FILE): $(COREAPI_OPTIONS_FILE) $(COREAPI_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(COREAPI_OPTIONS_FILE),$(COREAPI_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(COREAPI_OPTIONS_FILE) @$(COREAPI_PACKAGES_FILE) + +# Create file with javadoc options in it +$(COREAPI_OPTIONS_FILE): $(COREAPI_OVERVIEW) + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "$(TAGS)" ; \ + $(ECHO) "-encoding ISO-8859-1" ; \ + $(ECHO) "-splitIndex" ; \ + $(ECHO) "-overview $(COREAPI_OVERVIEW)" ; \ + $(ECHO) "-doctitle '$(COREAPI_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(COREAPI_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(COREAPI_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(COREAPI_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + ) >> $@ +ifdef COREAPI_TOP_EARLYACCESS + @$(ECHO) "-top '$(COREAPI_TOP_EARLYACCESS)'" >> $@ +endif + +# Create a file with the package names in it +$(COREAPI_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(CORE_PKGS)) + $(prep-target) + $(call PackageFilter,$(CORE_PKGS)) + +############################################################# # -# end of production targets -############################################################# +# mirrordocs +# + +# Part of langtools +ifdef LANGTOOLS_DIST + ALL_OTHER_TARGETS += mirrordocs +endif -.PHONY: coredocs -coredocs: - @# ######## core packages ####################### - $(RM) -r $(DOCSDIR)/api - $(MKDIR) -p $(DOCSDIR)/api - $(JAVADOC_CMD) $(CORE_JAVADOCFLAGS) \ - -d $(DOCSDIR)/api \ - -sourcepath $(RELEASEDOCS_SRCPATH) \ - $(CORE_PKGS) +MIRROR_DOCDIR := $(JDK_API_DOCSDIR)/apt/mirror +MIRROR2COREAPI := ../../$(JDKJRE2COREAPI) +MIRROR_DOCTITLE := Mirror API +MIRROR_WINDOWTITLE := Mirror API +MIRROR_HEADER := Mirror API +MIRROR_BOTTOM := $(call CommonBottom,$(MIRROR_FIRST_COPYRIGHT_YEAR)) +MIRROR_GROUPNAME := Packages +MIRROR_OVERVIEW := $(IMPORTSRCDIR)/com/sun/mirror/overview.html +MIRROR_REGEXP := com.sun.mirror.* +# MIRROR_PKGS is located in NON_CORE_PKGS.gmk + +# The index.html, options, and packages files +MIRROR_INDEX_FILE = $(MIRROR_DOCDIR)/index.html +MIRROR_OPTIONS_FILE = $(DOCSTMPDIR)/mirror.options +MIRROR_PACKAGES_FILE = $(DOCSTMPDIR)/mirror.packages + +mirrordocs: $(MIRROR_INDEX_FILE) + +# Set relative location to core api document root +$(MIRROR_INDEX_FILE): GET2DOCSDIR=$(MIRROR2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(MIRROR_INDEX_FILE): $(MIRROR_OPTIONS_FILE) $(MIRROR_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(MIRROR_OPTIONS_FILE),$(MIRROR_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(MIRROR_OPTIONS_FILE) @$(MIRROR_PACKAGES_FILE) -.PHONY: mirrordocs -mirrordocs: - @# ######## mirror api for apt ################## - $(RM) -r $(MIRROR_DESTDIR) - $(MKDIR) -p $(MIRROR_DESTDIR) - $(JAVADOC_CMD) $(MIRROR_JAVADOCFLAGS) \ - -d $(MIRROR_DESTDIR) \ - -sourcepath $(RELEASEDOCS_SRCPATH) \ - $(MIRROR_LINKOPT) \ - $(MIRROR_PKGS) +# Create file with javadoc options in it +$(MIRROR_OPTIONS_FILE): $(MIRROR_OVERVIEW) + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-overview $(MIRROR_OVERVIEW)" ; \ + $(ECHO) "-doctitle '$(MIRROR_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(MIRROR_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(MIRROR_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(MIRROR_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-group $(MIRROR_GROUPNAME) $(MIRROR_REGEXP)" ; \ + $(ECHO) "-linkoffline $(MIRROR2COREAPI) $(COREAPI_DOCSDIR)/"; \ + ) >> $@ + +# Create a file with the package names in it +$(MIRROR_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(MIRROR_PKGS)) + $(prep-target) + $(call PackageFilter,$(MIRROR_PKGS)) + +############################################################# +# +# docletapidocs +# + +# Part of langtools +ifdef LANGTOOLS_DIST + ALL_OTHER_TARGETS += docletapidocs +endif + +DOCLETAPI_DOCDIR := $(JDK_API_DOCSDIR)/javadoc/doclet +DOCLETAPI2COREAPI := ../../$(JDKJRE2COREAPI) +DOCLETAPI_DOCTITLE := Doclet API +DOCLETAPI_WINDOWTITLE := Doclet API +DOCLETAPI_HEADER := Doclet API +DOCLETAPI_BOTTOM := $(call CommonTrademarkBottom,$(DOCLETAPI_FIRST_COPYRIGHT_YEAR)) +DOCLETAPI_GROUPNAME := Packages +DOCLETAPI_REGEXP := com.sun.javadoc +# DOCLETAPI_PKGS is located in NON_CORE_PKGS.gmk + +# The index.html, options, and packages files +DOCLETAPI_INDEX_FILE = $(DOCLETAPI_DOCDIR)/index.html +DOCLETAPI_OPTIONS_FILE = $(DOCSTMPDIR)/docletapi.options +DOCLETAPI_PACKAGES_FILE = $(DOCSTMPDIR)/docletapi.packages + +docletapidocs: $(DOCLETAPI_INDEX_FILE) -.PHONY: docletapidocs -docletapidocs: - @# ######## doclet api ############################ - $(RM) -r $(DOCSDIR)/jdk/api/javadoc/doclet - $(MKDIR) -p $(DOCSDIR)/jdk/api/javadoc/doclet - $(JAVADOC_CMD) $(DOCLETAPI_JAVADOCFLAGS) \ - -d $(DOCSDIR)/jdk/api/javadoc/doclet \ - -sourcepath $(RELEASEDOCS_SRCPATH) \ - $(DOCLETAPI_LINKOPT) \ - $(DOCLETAPI_PKGS) +# Set relative location to core api document root +$(DOCLETAPI_INDEX_FILE): GET2DOCSDIR=$(DOCLETAPI2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(DOCLETAPI_INDEX_FILE): $(DOCLETAPI_OPTIONS_FILE) $(DOCLETAPI_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(DOCLETAPI_OPTIONS_FILE),$(DOCLETAPI_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(DOCLETAPI_OPTIONS_FILE) @$(DOCLETAPI_PACKAGES_FILE) + +# Create file with javadoc options in it +$(DOCLETAPI_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-breakiterator" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-doctitle '$(DOCLETAPI_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(DOCLETAPI_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(DOCLETAPI_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(DOCLETAPI_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-group $(DOCLETAPI_GROUPNAME) $(DOCLETAPI_REGEXP)" ; \ + $(ECHO) "-linkoffline $(DOCLETAPI2COREAPI) $(COREAPI_DOCSDIR)/"; \ + ) >> $@ + +# Create a file with the package names in it +$(DOCLETAPI_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(DOCLETAPI_PKGS)) + $(prep-target) + $(call PackageFilter,$(DOCLETAPI_PKGS)) + +############################################################# +# +# tagletapidocs +# + +# Part of langtools +ifdef LANGTOOLS_DIST + ALL_OTHER_TARGETS += tagletapidocs +endif + +TAGLETAPI_DOCDIR := $(JDK_API_DOCSDIR)/javadoc/taglet +TAGLETAPI2COREAPI := ../../$(JDKJRE2COREAPI) +TAGLETAPI_BOTTOM := $(call CommonTrademarkBottom,$(TAGLETAPI_FIRST_COPYRIGHT_YEAR)) +# TAGLETAPI_FILE is located in NON_CORE_PKGS.gmk + +# Temporary directory (special generation rules) +TAGLETAPI_TEMPDIR = $(DOCSTMPDIR)/taglets_temp + +# The index.html, options, and packages files +TAGLETAPI_INDEX_FILE = $(TAGLETAPI_DOCDIR)/index.html +TAGLETAPI_OPTIONS_FILE = $(DOCSTMPDIR)/tagletapi.options +TAGLETAPI_PACKAGES_FILE = $(DOCSTMPDIR)/tagletapi.packages + +tagletapidocs: $(TAGLETAPI_INDEX_FILE) + +# Set relative location to core api document root +$(TAGLETAPI_INDEX_FILE): GET2DOCSDIR=$(TAGLETAPI2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(TAGLETAPI_INDEX_FILE): $(TAGLETAPI_OPTIONS_FILE) $(TAGLETAPI_PACKAGES_FILE) + $(prep-javadoc) + $(RM) -r $(TAGLETAPI_TEMPDIR) + $(MKDIR) -p $(TAGLETAPI_TEMPDIR) + $(call JavadocSummary,$(TAGLETAPI_OPTIONS_FILE),$(TAGLETAPI_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(TAGLETAPI_TEMPDIR) \ + @$(TAGLETAPI_OPTIONS_FILE) @$(TAGLETAPI_PACKAGES_FILE) + cp -r $(TAGLETAPI_TEMPDIR)/com $(@D) + cp $(TAGLETAPI_TEMPDIR)/stylesheet.css $(@D) + $(RM) -r $(TAGLETAPI_TEMPDIR) -.PHONY: tagletapidocs -tagletapidocs: - @# ######## taglet api ############################ - $(RM) -r $(DOCSDIR)/jdk/api/javadoc/taglet - $(MKDIR) -p $(DOCSDIR)/jdk/api/javadoc/taglet - $(RM) -r $(DOCSTMPDIR) - $(MKDIR) -p $(DOCSTMPDIR) - $(JAVADOC_CMD) $(TAGLETAPI_JAVADOCFLAGS) \ - -d $(DOCSTMPDIR) \ - -linkoffline ../../../../api $(DOCSDIR)/api/ \ - $(IMPORTSRCDIR)/$(TAGLETAPI_FILE) - cp -r $(DOCSTMPDIR)/com $(DOCSDIR)/jdk/api/javadoc/taglet - cp $(DOCSTMPDIR)/stylesheet.css $(DOCSDIR)/jdk/api/javadoc/taglet - $(RM) -r $(DOCSTMPDIR) +# Create file with javadoc options in it +$(TAGLETAPI_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-nonavbar" ; \ + $(ECHO) "-noindex" ; \ + $(ECHO) "-bottom '$(TAGLETAPI_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(TAGLETAPI2COREAPI) $(COREAPI_DOCSDIR)/"; \ + ) >> $@ + +# Create a file with the package names in it +$(TAGLETAPI_PACKAGES_FILE): $(IMPORTSRCDIR)/$(TAGLETAPI_FILE) + $(prep-target) + @($(ECHO) "$(IMPORTSRCDIR)/$(TAGLETAPI_FILE)" ) > $@ + +############################################################# +# +# domapidocs +# + +ALL_OTHER_TARGETS += domapidocs + +DOMAPI_DOCDIR := $(JRE_API_DOCSDIR)/plugin/dom +DOMAPI2COREAPI := ../../$(JDKJRE2COREAPI) +DOMAPI_DOCTITLE := Common DOM API +DOMAPI_WINDOWTITLE := Common DOM API +DOMAPI_HEADER := Common DOM API +DOMAPI_BOTTOM := $(call CommonTrademarkBottom,$(DOMAPI_FIRST_COPYRIGHT_YEAR)) +DOMAPI_GROUPNAME := Packages +DOMAPI_REGEXP := com.sun.java.browser.dom:org.w3c.dom* +# DOMAPI_PKGS is located in NON_CORE_PKGS.gmk + +# The index.html, options, and packages files +DOMAPI_INDEX_FILE = $(DOMAPI_DOCDIR)/index.html +DOMAPI_OPTIONS_FILE = $(DOCSTMPDIR)/domapi.options +DOMAPI_PACKAGES_FILE = $(DOCSTMPDIR)/domapi.packages -.PHONY: domapidocs -domapidocs: - @# ######## dom api ############################ - $(RM) -r $(DOCSDIR)/jre/api/plugin/dom - $(MKDIR) -p $(DOCSDIR)/jre/api/plugin/dom - $(JAVADOC_CMD) $(DOMAPI_JAVADOCFLAGS) \ - -d $(DOCSDIR)/jre/api/plugin/dom \ - -sourcepath $(RELEASEDOCS_SRCPATH) \ - -linkoffline ../../../../api $(DOCSDIR)/api/ \ - $(DOMAPI_PKGS) +domapidocs: $(DOMAPI_INDEX_FILE) + +# Set relative location to core api document root +$(DOMAPI_INDEX_FILE): GET2DOCSDIR=$(DOMAPI2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(DOMAPI_INDEX_FILE): $(DOMAPI_OPTIONS_FILE) $(DOMAPI_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(DOMAPI_OPTIONS_FILE),$(DOMAPI_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(DOMAPI_OPTIONS_FILE) @$(DOMAPI_PACKAGES_FILE) -.PHONY: jpdadocs +# Create file with javadoc options in it +$(DOMAPI_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-splitIndex" ; \ + $(ECHO) "-doctitle '$(DOMAPI_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(DOMAPI_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(DOMAPI_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(DOMAPI_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-group $(DOMAPI_GROUPNAME) $(DOMAPI_REGEXP)" ; \ + $(ECHO) "-linkoffline $(DOMAPI2COREAPI) $(COREAPI_DOCSDIR)/" ; \ + ) >> $@ + +# Create a file with the package names in it +$(DOMAPI_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(DOMAPI_PKGS)) + $(prep-target) + $(call PackageFilter,$(DOMAPI_PKGS)) + +############################################################# +# +# jpdadocs +# + +ALL_OTHER_TARGETS += jpdadocs + jpdadocs: jdidocs jdwpdocs jvmtidocs -.PHONY: jdidocs -jdidocs: - @# ######## jdi ################################# - $(RM) -r $(DOCSDIR)/jdk/api/jpda/jdi - $(MKDIR) -p $(DOCSDIR)/jdk/api/jpda/jdi - $(JAVADOC_CMD) $(JDI_JAVADOCFLAGS) \ - $(JDI_PKGS) +############################################################# +# +# jdidocs +# + +ALL_OTHER_TARGETS += jdidocs + +JDI_DOCDIR := $(JDK_API_DOCSDIR)/jpda/jdi +JDI2COREAPI := ../../$(JDKJRE2COREAPI) +JDI_DOCTITLE := Java$(TRADEMARK) Debug Interface +JDI_WINDOWTITLE := Java Debug Interface +JDI_HEADER := Java Debug Interface +JDI_BOTTOM := $(call CommonBottom,$(JDI_FIRST_COPYRIGHT_YEAR)) +JDI_OVERVIEW := $(SHARE_SRC)/classes/jdi-overview.html +# JDI_PKGS is located in NON_CORE_PKGS.gmk + +# The index.html, options, and packages files +JDI_INDEX_FILE = $(JDI_DOCDIR)/index.html +JDI_OPTIONS_FILE = $(DOCSTMPDIR)/jdi.options +JDI_PACKAGES_FILE = $(DOCSTMPDIR)/jdi.packages + +jdidocs: $(JDI_INDEX_FILE) + +# Set relative location to core api document root +$(JDI_INDEX_FILE): GET2DOCSDIR=$(JDI2COREAPI)/.. +# Run javadoc if the index file is out of date or missing +$(JDI_INDEX_FILE): $(JDI_OPTIONS_FILE) $(JDI_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(JDI_OPTIONS_FILE),$(JDI_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(JDI_OPTIONS_FILE) @$(JDI_PACKAGES_FILE) + +# Create file with javadoc options in it +$(JDI_OPTIONS_FILE): $(JDI_OVERVIEW) + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-overview $(JDI_OVERVIEW)" ; \ + $(ECHO) "-doctitle '$(JDI_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(JDI_WINDOWTITLE) $(DRAFT_WINTITLE)'" ; \ + $(ECHO) "-header '$(JDI_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(JDI_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(JDI2COREAPI) $(COREAPI_DOCSDIR)/" ; \ + ) >> $@ + +# Create a file with the package names in it +$(JDI_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(JDI_PKGS)) + $(prep-target) + $(call PackageFilter,$(JDI_PKGS)) + +############################################################# +# +# jdwpdocs +# + +ALL_OTHER_TARGETS += jdwpdocs + +JDWP_DOCDIR = $(PLATFORM_DOCSDIR)/jpda/jdwp JDWP_SPEC = $(BUILDDIR)/jpda/jdwp/jdwp.spec -JDWP_DOC = $(DOCSDIR)/platform/jpda/jdwp/jdwp-protocol.html JDWPGEN_JARFILE = $(BUILDTOOLJARDIR)/jdwpgen.jar -.PHONY: jdwpdocs -jdwpdocs: $(JDWP_DOC) +jdwpdocs: $(JDWP_DOCDIR)/jdwp-protocol.html +$(JDWP_DOCDIR)/jdwp-protocol.html: $(JDWPGEN_JARFILE) $(JDWP_SPEC) + $(prep-javadoc) + $(BOOT_JAVA_CMD) -jar $(JDWPGEN_JARFILE) $(JDWP_SPEC) -doc $@ -$(JDWP_DOC): $(JDWPGEN_JARFILE) $(JDWP_SPEC) - $(prep-target) - $(BOOT_JAVA_CMD) -jar $(JDWPGEN_JARFILE) $(JDWP_SPEC) -doc $(JDWP_DOC) +############################################################# +# +# jvmtidocs +# + +ALL_OTHER_TARGETS += jvmtidocs -.PHONY: jvmtidocs -jvmtidocs: - @# ######## jvmti ################################# - @if [ -f $(JVMTI_HTML) ] ; then \ - $(RM) -r $(DOCSDIR)/$(JVMTI_DOCS_SUBDIR); \ - $(MKDIR) -p $(DOCSDIR)/$(JVMTI_DOCS_SUBDIR); \ - $(ECHO) $(CP) $(JVMTI_HTML) $(DOCSDIR)/$(JVMTI_DOCS_SUBDIR); \ - $(CP) $(JVMTI_HTML) $(DOCSDIR)/$(JVMTI_DOCS_SUBDIR); \ - else \ - $(ECHO) "WARNING: Generated jvmti file does not exist: $(JVMTI_HTML)"; \ +JVMTI_DOCDIR = $(PLATFORM_DOCSDIR)/jvmti +JVMTI_HTML = $(HOTSPOT_DOCS_IMPORT_PATH)/platform/jvmti/jvmti.html + +jvmtidocs: $(JVMTI_DOCDIR)/jvmti.html +$(JVMTI_DOCDIR)/jvmti.html: + @$(prep-javadoc) + @if [ -f $(JVMTI_HTML) ] ; then \ + $(ECHO) "$(CP) $(JVMTI_HTML) $@"; \ + $(CP) $(JVMTI_HTML) $@; \ + else \ + $(ECHO) "WARNING: Generated file does not exist: $(JVMTI_HTML)"; \ fi -.PHONY: jaasdocs -jaasdocs: - @# ######## api-jaas ############################ - $(RM) -r $(JAAS_DOCDIR) - $(MKDIR) -p $(JAAS_DOCDIR) - $(JAVADOC_CMD) $(JAAS_JAVADOCFLAGS) \ - $(JAAS_PKGS) +############################################################# +# +# jaasdocs +# + +ALL_OTHER_TARGETS += jaasdocs + +JAAS_DOCDIR := $(JRE_API_DOCSDIR)/security/jaas/spec +JAAS2COREAPI := ../../../$(JDKJRE2COREAPI) +JAAS_DOCTITLE := Java$(TRADEMARK) Authentication and Authorization Service +JAAS_WINDOWTITLE := Java Authentication and Authorization Service +JAAS_HEADER := Java Authentication and Authorization Service +JAAS_BOTTOM := $(call CommonBottom,$(JAAS_FIRST_COPYRIGHT_YEAR)) +# JAAS_PKGS is located in NON_CORE_PKGS.gmk +JAAS_OVERVIEW := $(SHARE_SRC)/classes/com/sun/security/auth/jaas-overview.html + +# The index.html, options, and packages files +JAAS_INDEX_FILE = $(JAAS_DOCDIR)/index.html +JAAS_OPTIONS_FILE = $(DOCSTMPDIR)/jaas.options +JAAS_PACKAGES_FILE = $(DOCSTMPDIR)/jaas.packages + +jaasdocs: $(JAAS_INDEX_FILE) + +# Set relative location to core api document root +$(JAAS_INDEX_FILE): GET2DOCSDIR=$(JAAS2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(JAAS_INDEX_FILE): $(JAAS_OPTIONS_FILE) $(JAAS_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(JAAS_OPTIONS_FILE),$(JAAS_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(JAAS_OPTIONS_FILE) @$(JAAS_PACKAGES_FILE) + +# Create file with javadoc options in it +$(JAAS_OPTIONS_FILE): $(JAAS_OVERVIEW) + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-overview $(JAAS_OVERVIEW)" ; \ + $(ECHO) "-doctitle '$(JAAS_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(JAAS_WINDOWTITLE) $(DRAFT_WINTITLE)'"; \ + $(ECHO) "-header '$(JAAS_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(JAAS_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(JAAS2COREAPI) $(COREAPI_DOCSDIR)/" ; \ + ) >> $@ + +# Create a file with the package names in it +$(JAAS_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(JAAS_PKGS)) + $(prep-target) + $(call PackageFilter,$(JAAS_PKGS)) + +############################################################# +# +# jgssdocs +# + +ALL_OTHER_TARGETS += jgssdocs + +JGSS_DOCDIR := $(JRE_API_DOCSDIR)/security/jgss/spec +JGSS2COREAPI := ../../../$(JDKJRE2COREAPI) +JGSS_DOCTITLE := Java$(TRADEMARK) GSS-API Utilities +JGSS_WINDOWTITLE := Java GSS-API Utilities +JGSS_HEADER := Java GSS-API Utilities +JGSS_BOTTOM := $(call CommonBottom,$(JGSS_FIRST_COPYRIGHT_YEAR)) +JGSS_OVERVIEW := $(SHARE_SRC)/classes/com/sun/security/jgss/jgss-overview.html +# JGSS_PKGS is located in NON_CORE_PKGS.gmk -.PHONY: jgssdocs -jgssdocs: - @# ######## api-jgss ############################ - $(RM) -r $(JGSS_DOCDIR) - $(MKDIR) -p $(JGSS_DOCDIR) - $(JAVADOC_CMD) $(JGSS_JAVADOCFLAGS) \ - $(JGSS_PKGS) +# The index.html, options, and packages files +JGSS_INDEX_FILE = $(JGSS_DOCDIR)/index.html +JGSS_OPTIONS_FILE = $(DOCSTMPDIR)/jgss.options +JGSS_PACKAGES_FILE = $(DOCSTMPDIR)/jgss.packages + +jgssdocs: $(JGSS_INDEX_FILE) + +# Set relative location to core api document root +$(JGSS_INDEX_FILE): GET2DOCSDIR=$(JGSS2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(JGSS_INDEX_FILE): $(JGSS_OPTIONS_FILE) $(JGSS_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(JGSS_OPTIONS_FILE),$(JGSS_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(JGSS_OPTIONS_FILE) @$(JGSS_PACKAGES_FILE) + +# Create file with javadoc options in it +$(JGSS_OPTIONS_FILE): $(JGSS_OVERVIEW) + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-nodeprecatedlist" ; \ + $(ECHO) "-overview $(JGSS_OVERVIEW)" ; \ + $(ECHO) "-doctitle '$(JGSS_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(JGSS_WINDOWTITLE) $(DRAFT_WINTITLE)'"; \ + $(ECHO) "-header '$(JGSS_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(JGSS_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(JGSS2COREAPI) $(COREAPI_DOCSDIR)/" ; \ + ) >> $@ + +# Create a file with the package names in it +$(JGSS_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(JGSS_PKGS)) + $(prep-target) + $(call PackageFilter,$(JGSS_PKGS)) + +############################################################# +# +# smartcardiodocs +# + +ALL_OTHER_TARGETS += smartcardiodocs + +SMARTCARDIO_DOCDIR := $(JRE_API_DOCSDIR)/security/smartcardio/spec +SMARTCARDIO2COREAPI := ../../../$(JDKJRE2COREAPI) +SMARTCARDIO_DOCTITLE := Java$(TRADEMARK) Smart Card I/O +SMARTCARDIO_WINDOWTITLE := Java Smart Card I/O +SMARTCARDIO_HEADER := Java Smart Card I/O +SMARTCARDIO_BOTTOM := $(call CommonBottom,$(SMARTCARDIO_FIRST_COPYRIGHT_YEAR)) +# SMARTCARDIO_PKGS is located in NON_CORE_PKGS.gmk + +# The index.html, options, and packages files +SMARTCARDIO_INDEX_FILE = $(SMARTCARDIO_DOCDIR)/index.html +SMARTCARDIO_OPTIONS_FILE = $(DOCSTMPDIR)/smartcardio.options +SMARTCARDIO_PACKAGES_FILE = $(DOCSTMPDIR)/smartcardio.packages + +smartcardiodocs: $(SMARTCARDIO_INDEX_FILE) + +# Set relative location to core api document root +$(SMARTCARDIO_INDEX_FILE): GET2DOCSDIR=$(SMARTCARDIO2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(SMARTCARDIO_INDEX_FILE): $(SMARTCARDIO_OPTIONS_FILE) $(SMARTCARDIO_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(SMARTCARDIO_OPTIONS_FILE),$(SMARTCARDIO_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(SMARTCARDIO_OPTIONS_FILE) @$(SMARTCARDIO_PACKAGES_FILE) -.PHONY: smartcardiodocs -smartcardiodocs: - @# ######## api-smartcardio ############################ - $(RM) -r $(SMARTCARDIO_DOCDIR) - $(MKDIR) -p $(SMARTCARDIO_DOCDIR) - $(JAVADOC_CMD) $(SMARTCARDIO_JAVADOCFLAGS) \ - $(SMARTCARDIO_PKGS) +# Create file with javadoc options in it +$(SMARTCARDIO_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-nodeprecatedlist" ; \ + $(ECHO) "-doctitle '$(SMARTCARDIO_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(SMARTCARDIO_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(SMARTCARDIO_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(SMARTCARDIO_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(SMARTCARDIO2COREAPI) $(COREAPI_DOCSDIR)/"; \ + ) >> $@ + +# Create a file with the package names in it +$(SMARTCARDIO_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(SMARTCARDIO_PKGS)) + $(prep-target) + $(call PackageFilter,$(SMARTCARDIO_PKGS)) + +############################################################# +# +# httpserverdocs +# + +ALL_OTHER_TARGETS += httpserverdocs + +HTTPSERVER_DOCDIR := $(JRE_API_DOCSDIR)/net/httpserver/spec +HTTPSERVER2COREAPI := ../../../$(JDKJRE2COREAPI) +HTTPSERVER_DOCTITLE := Java$(TRADEMARK) HTTP Server +HTTPSERVER_WINDOWTITLE := Java HTTP Server +HTTPSERVER_HEADER := Java HTTP Server +HTTPSERVER_BOTTOM := $(call CommonBottom,$(HTTPSERVER_FIRST_COPYRIGHT_YEAR)) +# HTTPSERVER_PKGS is located in NON_CORE_PKGS.gmk + +HTTPSERVER_INDEX_HTML = $(HTTPSERVER_DOCDIR)/index.html +HTTPSERVER_OPTIONS_FILE = $(DOCSTMPDIR)/httpserver.options +HTTPSERVER_PACKAGES_FILE = $(DOCSTMPDIR)/httpserver.packages + +httpserverdocs: $(HTTPSERVER_INDEX_HTML) + +# Set relative location to core api document root +$(HTTPSERVER_INDEX_HTML): GET2DOCSDIR=$(HTTPSERVER2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(HTTPSERVER_INDEX_HTML): $(HTTPSERVER_OPTIONS_FILE) $(HTTPSERVER_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(HTTPSERVER_OPTIONS_FILE),$(HTTPSERVER_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(HTTPSERVER_OPTIONS_FILE) @$(HTTPSERVER_PACKAGES_FILE) + +# Create file with javadoc options in it +$(HTTPSERVER_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-nodeprecatedlist" ; \ + $(ECHO) "-doctitle '$(HTTPSERVER_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(HTTPSERVER_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(HTTPSERVER_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(HTTPSERVER_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(HTTPSERVER2COREAPI) $(COREAPI_DOCSDIR)/"; \ + ) >> $@ -.PHONY: tracingdocs -tracingdocs: - @# ######## api-tracing ############################ - $(RM) -r $(TRACING_DOCDIR) - $(MKDIR) -p $(TRACING_DOCDIR) - $(JAVADOC_CMD) $(TRACING_JAVADOCFLAGS) \ - $(TRACING_PKGS) +# Create a file with the package names in it +$(HTTPSERVER_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(HTTPSERVER_PKGS)) + $(prep-target) + $(call PackageFilter,$(HTTPSERVER_PKGS)) + +############################################################# +# +# mgmtdocs +# + +ALL_OTHER_TARGETS += mgmtdocs + +MGMT_DOCDIR := $(JRE_API_DOCSDIR)/management/extension +MGMT2COREAPI := ../../$(JDKJRE2COREAPI) +JVM_MIB_NAME := JVM-MANAGEMENT-MIB.mib +JVM_MIB_SRC := $(CLOSED_SRC)/share/classes/sun/management/snmp/$(JVM_MIB_NAME) +MGMT_DOCTITLE := Monitoring and Management Interface for the Java$(TRADEMARK) Platform +MGMT_WINDOWTITLE := Monitoring and Management Interface for the Java Platform +MGMT_HEADER := Monitoring and Management Interface for the Java Platform +MGMT_BOTTOM := $(call CommonBottom,$(MGMT_FIRST_COPYRIGHT_YEAR)) +MGMT_OVERVIEW := $(SHARE_SRC)/classes/com/sun/management/mgmt-overview.html +# MGMT_PKGS is located in NON_CORE_PKGS.gmk + +# The index.html, options, and packages files +MGMT_INDEX_FILE = $(MGMT_DOCDIR)/index.html +MGMT_OPTIONS_FILE = $(DOCSTMPDIR)/mgmt.options +MGMT_PACKAGES_FILE = $(DOCSTMPDIR)/mgmt.packages + +mgmtdocs: $(MGMT_INDEX_FILE) + +# Set relative location to core api document root +$(MGMT_INDEX_FILE): GET2DOCSDIR=$(MGMT2COREAPI)/.. -.PHONY: httpserverdocs -httpserverdocs: - @# ######## api-httpserver ####################### - $(RM) -r $(HTTPSERVER_DOCDIR) - $(MKDIR) -p $(HTTPSERVER_DOCDIR) - $(JAVADOC_CMD) $(HTTPSERVER_JAVADOCFLAGS) \ - $(HTTPSERVER_PKGS) +# Run javadoc if the index file is out of date or missing +$(MGMT_INDEX_FILE): $(MGMT_OPTIONS_FILE) $(MGMT_PACKAGES_FILE) + $(prep-javadoc) + @if [ -f $(JVM_MIB_SRC) ] ; then \ + $(ECHO) "$(CP) $(JVM_MIB_SRC) $(@D)/.."; \ + $(CP) $(JVM_MIB_SRC) $(@D)/.. ; \ + else \ + $(ECHO) "WARNING: File $(JVM_MIB_NAME) not available."; \ + fi + $(call JavadocSummary,$(MGMT_OPTIONS_FILE),$(MGMT_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(MGMT_OPTIONS_FILE) @$(MGMT_PACKAGES_FILE) + +# Create file with javadoc options in it +$(MGMT_OPTIONS_FILE): $(MGMT_OVERVIEW) + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-nodeprecatedlist" ; \ + $(ECHO) "-overview $(MGMT_OVERVIEW)" ; \ + $(ECHO) "-doctitle '$(MGMT_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(MGMT_WINDOWTITLE) $(DRAFT_WINTITLE)'"; \ + $(ECHO) "-header '$(MGMT_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(MGMT_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(MGMT2COREAPI) $(COREAPI_DOCSDIR)/" ; \ + ) >> $@ + +# Create a file with the package names in it +$(MGMT_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(MGMT_PKGS)) + $(prep-target) + $(call PackageFilter,$(MGMT_PKGS)) + +############################################################# +# +# attachdocs +# + +ALL_OTHER_TARGETS += attachdocs -.PHONY: sctpdocs -sctpdocs: - @# ######## api-sctp ####################### - $(RM) -r $(SCTPAPI_DOCDIR) - $(MKDIR) -p $(SCTPAPI_DOCDIR) - $(JAVADOC_CMD) $(SCTPAPI_JAVADOCFLAGS) \ - $(SCTPAPI_PKGS) +ATTACH_DOCDIR := $(JDK_API_DOCSDIR)/attach/spec +ATTACH2COREAPI := ../../$(JDKJRE2COREAPI) +ATTACH_DOCTITLE := Attach API +ATTACH_WINDOWTITLE := Attach API +ATTACH_HEADER := Attach API +ATTACH_BOTTOM := $(call CommonBottom,$(ATTACH_FIRST_COPYRIGHT_YEAR)) +# ATTACH_PKGS is located in NON_CORE_PKGS.gmk + +ATTACH_INDEX_HTML = $(ATTACH_DOCDIR)/index.html +ATTACH_OPTIONS_FILE = $(DOCSTMPDIR)/attach.options +ATTACH_PACKAGES_FILE = $(DOCSTMPDIR)/attach.packages + +attachdocs: $(ATTACH_INDEX_HTML) + +# Set relative location to core api document root +$(ATTACH_INDEX_HTML): GET2DOCSDIR=$(ATTACH2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(ATTACH_INDEX_HTML): $(ATTACH_OPTIONS_FILE) $(ATTACH_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(ATTACH_OPTIONS_FILE),$(ATTACH_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(ATTACH_OPTIONS_FILE) @$(ATTACH_PACKAGES_FILE) + +# Create file with javadoc options in it +$(ATTACH_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-nodeprecatedlist" ; \ + $(ECHO) "-doctitle '$(ATTACH_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(ATTACH_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(ATTACH_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(ATTACH_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(ATTACH2COREAPI) $(COREAPI_DOCSDIR)/" ; \ + ) >> $@ + +# Create a file with the package names in it +$(ATTACH_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(ATTACH_PKGS)) + $(prep-target) + $(call PackageFilter,$(ATTACH_PKGS)) + +############################################################# +# +# jconsoledocs +# + +ALL_OTHER_TARGETS += jconsoledocs + +JCONSOLE_DOCDIR := $(JDK_API_DOCSDIR)/jconsole/spec +JCONSOLE2COREAPI := ../../$(JDKJRE2COREAPI) +JCONSOLE_DOCTITLE := JConsole API +JCONSOLE_WINDOWTITLE := JConsole API +JCONSOLE_HEADER := JConsole API +JCONSOLE_BOTTOM := $(call CommonBottom,$(JCONSOLE_FIRST_COPYRIGHT_YEAR)) +# JCONSOLE_PKGS is located in NON_CORE_PKGS.gmk + +JCONSOLE_INDEX_HTML = $(JCONSOLE_DOCDIR)/index.html +JCONSOLE_OPTIONS_FILE = $(DOCSTMPDIR)/jconsole.options +JCONSOLE_PACKAGES_FILE = $(DOCSTMPDIR)/jconsole.packages + +jconsoledocs: $(JCONSOLE_INDEX_HTML) -.PHONY: mgmtdocs -mgmtdocs: $(COPY-MIB-TARGET) - @# ######## api-management ############################ - $(RM) -r $(MGMT_EXT_DIR) - $(MKDIR) -p $(MGMT_EXT_DIR) - $(JAVADOC_CMD) $(MGMT_JAVADOCFLAGS) \ - $(MGMT_PKGS) +# Set relative location to core api document root +$(JCONSOLE_INDEX_HTML): GET2DOCSDIR=$(JCONSOLE2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(JCONSOLE_INDEX_HTML): $(JCONSOLE_OPTIONS_FILE) $(JCONSOLE_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(JCONSOLE_OPTIONS_FILE),$(JCONSOLE_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(JCONSOLE_OPTIONS_FILE) @$(JCONSOLE_PACKAGES_FILE) + +# Create file with javadoc options in it +$(JCONSOLE_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-nodeprecatedlist" ; \ + $(ECHO) "-doctitle '$(JCONSOLE_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(JCONSOLE_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(JCONSOLE_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(JCONSOLE_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(JCONSOLE2COREAPI) $(COREAPI_DOCSDIR)/"; \ + ) >> $@ + +# Create a file with the package names in it +$(JCONSOLE_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(JCONSOLE_PKGS)) + $(prep-target) + $(call PackageFilter,$(JCONSOLE_PKGS)) -copy-mib: - @# ######## copy-snmp-mib ############################ - $(RM) $(MGMT_DOCDIR)/$(JVM_MIB_NAME) - $(MKDIR) -p $(MGMT_DOCDIR) - $(CP) $(JVM_MIB_SRC) $(MGMT_DOCDIR) +############################################################# +# +# treeapidocs +# + +# Part of langtools +ifdef LANGTOOLS_DIST + ALL_OTHER_TARGETS += treeapidocs +endif + +TREEAPI_DOCDIR := $(JDK_API_DOCSDIR)/javac/tree +TREEAPI2COREAPI := ../../$(JDKJRE2COREAPI) +TREEAPI_DOCTITLE := Compiler Tree API +TREEAPI_WINDOWTITLE := Compiler Tree API +TREEAPI_HEADER := Compiler Tree API +TREEAPI_BOTTOM := $(call CommonBottom,$(TREEAPI_FIRST_COPYRIGHT_YEAR)) +TREEAPI_GROUPNAME := Packages +TREEAPI_REGEXP := com.sun.source.* +# TREEAPI_PKGS is located in NON_CORE_PKGS.gmk + +TREEAPI_INDEX_HTML = $(TREEAPI_DOCDIR)/index.html +TREEAPI_OPTIONS_FILE = $(DOCSTMPDIR)/treeapi.options +TREEAPI_PACKAGES_FILE = $(DOCSTMPDIR)/treeapi.packages + +treeapidocs: $(TREEAPI_INDEX_HTML) + +# Set relative location to core api document root +$(TREEAPI_INDEX_HTML): GET2DOCSDIR=$(TREEAPI2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(TREEAPI_INDEX_HTML): $(TREEAPI_OPTIONS_FILE) $(TREEAPI_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(TREEAPI_OPTIONS_FILE),$(TREEAPI_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(TREEAPI_OPTIONS_FILE) @$(TREEAPI_PACKAGES_FILE) -.PHONY: attachdocs -attachdocs: - @# ######## api-attach ############################ - $(RM) -r $(ATTACH_DOCDIR) - $(MKDIR) -p $(ATTACH_DOCDIR) - $(JAVADOC_CMD) $(ATTACH_JAVADOCFLAGS) \ - $(ATTACH_PKGS) +# Create file with javadoc options in it +$(TREEAPI_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-doctitle '$(TREEAPI_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(TREEAPI_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(TREEAPI_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(TREEAPI_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-group $(TREEAPI_GROUPNAME) $(TREEAPI_REGEXP)" ; \ + $(ECHO) "-linkoffline $(TREEAPI2COREAPI) $(COREAPI_DOCSDIR)/" ; \ + ) >> $@ + +# Create a file with the package names in it +$(TREEAPI_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(TREEAPI_PKGS)) + $(prep-target) + $(call PackageFilter,$(TREEAPI_PKGS)) + +############################################################# +# +# sctpdocs +# + +ALL_OTHER_TARGETS += sctpdocs + +SCTPAPI_DOCDIR := $(JRE_API_DOCSDIR)/nio/sctp/spec +SCTPAPI2COREAPI := ../../../$(JDKJRE2COREAPI) +SCTPAPI_DOCTITLE := SCTP API +SCTPAPI_WINDOWTITLE := SCTP API +SCTPAPI_HEADER := SCTP API +SCTPAPI_BOTTOM := $(call CommonBottom,$(SCTPAPI_FIRST_COPYRIGHT_YEAR)) +# SCTPAPI_PKGS is located in NON_CORE_PKGS.gmk + +SCTPAPI_INDEX_HTML = $(SCTPAPI_DOCDIR)/index.html +SCTPAPI_OPTIONS_FILE = $(DOCSTMPDIR)/sctp.options +SCTPAPI_PACKAGES_FILE = $(DOCSTMPDIR)/sctp.packages + +sctpdocs: $(SCTPAPI_INDEX_HTML) + +# Set relative location to core api document root +$(SCTSCTSCTP: GET2DOCSDIR=$(SCTPAPI2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(SCTPAPI_INDEX_HTML): $(SCTPAPI_OPTIONS_FILE) $(SCTPAPI_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(SCTPAPI_OPTIONS_FILE),$(SCTPAPI_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(SCTPAPI_OPTIONS_FILE) @$(SCTPAPI_PACKAGES_FILE) + +# Create file with javadoc options in it +$(SCTPAPI_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-nodeprecatedlist" ; \ + $(ECHO) "-doctitle '$(SCTPAPI_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(SCTPAPI_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(SCTPAPI_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(SCTPAPI_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(SCTPAPI2COREAPI) $(COREAPI_DOCSDIR)/" ; \ + ) >> $@ + +# Create a file with the package names in it +$(SCTPAPI_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(SCTPAPI_PKGS)) + $(prep-target) + $(call PackageFilter,$(SCTPAPI_PKGS)) + +############################################################# +# +# tracingdocs +# -.PHONY: jconsoledocs -jconsoledocs: - @# ######## api-jconsole ############################ - $(RM) -r $(JCONSOLE_DOCDIR) - $(MKDIR) -p $(JCONSOLE_DOCDIR) - $(JAVADOC_CMD) $(JCONSOLE_JAVADOCFLAGS) \ - $(JCONSOLE_PKGS) +ALL_OTHER_TARGETS += tracingdocs + +TRACING_DOCDIR := $(JRE_API_DOCSDIR)/tracing +TRACING2COREAPI := ../$(JDKJRE2COREAPI) +TRACING_DOCTITLE := Java$(TRADEMARK) Platform Tracing +TRACING_WINDOWTITLE := Platform Tracing +TRACING_HEADER := Platform Tracing +TRACING_BOTTOM := $(call CommonBottom,$(TRACING_FIRST_COPYRIGHT_YEAR)) +# TRACING_PKGS is located in NON_CORE_PKGS.gmk + +TRACING_INDEX_HTML = $(TRACING_DOCDIR)/index.html +TRACING_OPTIONS_FILE = $(DOCSTMPDIR)/tracing.options +TRACING_PACKAGES_FILE = $(DOCSTMPDIR)/tracing.packages + +tracingdocs: $(TRACING_INDEX_HTML) + +# Set relative location to core api document root +$(TRACING_INDEX_HTML): GET2DOCSDIR=$(TRACING2COREAPI)/.. + +# Run javadoc if the index file is out of date or missing +$(TRACING_INDEX_HTML): $(TRACING_OPTIONS_FILE) $(TRACING_PACKAGES_FILE) + $(prep-javadoc) + $(call JavadocSummary,$(TRACING_OPTIONS_FILE),$(TRACING_PACKAGES_FILE)) + $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \ + @$(TRACING_OPTIONS_FILE) @$(TRACING_PACKAGES_FILE) -.PHONY: treeapidocs -treeapidocs: - @# ######## tree api for javac ################## - $(RM) -r $(TREEAPI_DESTDIR) - $(MKDIR) -p $(TREEAPI_DESTDIR) - $(JAVADOC_CMD) $(TREEAPI_JAVADOCFLAGS) \ - -d $(TREEAPI_DESTDIR) \ - -sourcepath $(RELEASEDOCS_SRCPATH) \ - $(TREEAPI_LINKOPT) \ - $(TREEAPI_PKGS) +# Create file with javadoc options in it +$(TRACING_OPTIONS_FILE): + $(prep-target) + @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \ + $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \ + $(ECHO) "-encoding ascii" ; \ + $(ECHO) "-nodeprecatedlist" ; \ + $(ECHO) "-doctitle '$(TRACING_DOCTITLE)'" ; \ + $(ECHO) "-windowtitle '$(TRACING_WINDOWTITLE) $(DRAFT_WINTITLE)'";\ + $(ECHO) "-header '$(TRACING_HEADER)$(DRAFT_HEADER)'" ; \ + $(ECHO) "-bottom '$(TRACING_BOTTOM)$(DRAFT_BOTTOM)'" ; \ + $(ECHO) "-linkoffline $(TRACING2COREAPI) $(COREAPI_DOCSDIR)/" ; \ + ) >> $@ + +# Create a file with the package names in it +$(TRACING_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(TRACING_PKGS)) + $(prep-target) + $(call PackageFilter,$(TRACING_PKGS)) + +############################################################# +# +# Get a cache of all the directories +$(DIRECTORY_CACHE): $(ALL_SOURCE_DIRS) + $(prep-target) + @for cp in $(ALL_SOURCE_DIRS) ; do \ + $(ECHO) "$(FIND) $${cp} -type f >> $@"; \ + $(FIND) $${cp} -type f >> $@; \ + done + +############################################################# +#release version of core packages ######## +# Maximize performance and ensure that build number & milestone are set. + +rel-coredocs: sanitycheckcoredocs + $(MAKE) coredocs + +rel-docs: rel-coredocs $(ALL_OTHER_TARGETS) +# +# end of production targets + +otherdocs: $(ALL_OTHER_TARGETS) + +clean: + $(RM) -r $(DOCSDIR) $(DOCSTMPDIR) + +############################################################# # DEBUG TARGET # List the values defined in the makefile hierarchy, to make sure everything # is set properly, and to help identify values we can use instead of making new ones. @@ -714,9 +1211,14 @@ # * BUILD_NUMBER defaults to b00 if not set on command line with BUILD_NUMBER= # * MILESTONE defaults to internal unless set to beta, rc, or fcs on command line # -.PHONY: echovalues + echovalues: @$(ECHO) "" + @$(ECHO) --------------Imports--------------------------- + @$(ECHO) "IMPORT_PACKAGES = $(IMPORT_PACKAGES)" + @$(ECHO) "IMPORT_PACKAGE_FILTER = $(IMPORT_PACKAGE_FILTER)" + @$(ECHO) --------------Imports--------------------------- + @$(ECHO) "" @$(ECHO) --------------Shared--------------------------- @$(ECHO) BUILD_NUMBER = $(BUILD_NUMBER) @$(ECHO) FULL_VERSION = $(FULL_VERSION) @@ -736,11 +1238,16 @@ @$(ECHO) --------------Shared--------------------------- @$(ECHO) "" @$(ECHO) --------------common/Defs--------------------------- - @$(ECHO) "RELEASEDOCS_SRCPATH" + @$(ECHO) "RELEASEDOCS_SOURCEPATH" @$(ECHO) " SHARE_SRC/classes: $(SHARE_SRC)/classes" @$(ECHO) " PLATFORM_SRC/classes: $(PLATFORM_SRC)/classes" @$(ECHO) " GENSRCDIR: $(GENSRCDIR)" + @$(ECHO) " SHARE_SRC/doc/stub: $(SHARE_SRC)/doc/stub" @$(ECHO) " IMPORTSRCDIR: $(IMPORTSRCDIR)" - @$(ECHO) " SHARE_SRC/doc/stub: $(SHARE_SRC)/doc/stub" @$(ECHO) --------------common/Defs--------------------------- @$(ECHO) "" + +############################################################# +.PHONY: all docs coredocs rel-docs echovalues otherdocs rel-coredocs \ + sanitycheckcoredocs $(ALL_OTHER_TARGETS) + diff -r c4a3e3140f7b -r 88db80c8e49c jdk/make/java/java/FILES_java.gmk --- a/jdk/make/java/java/FILES_java.gmk Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/make/java/java/FILES_java.gmk Wed Jul 05 17:18:12 2017 +0200 @@ -30,6 +30,7 @@ # JAVA_JAVA_java = \ java/lang/Object.java \ + java/lang/AutoCloseable.java \ java/lang/Class.java \ java/lang/Thread.java \ java/lang/Character.java \ diff -r c4a3e3140f7b -r 88db80c8e49c jdk/make/java/security/Makefile --- a/jdk/make/java/security/Makefile Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/make/java/security/Makefile Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1996, 2010 Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,11 @@ CACERTS_SRC = $(CACERTS_FILE) CACERTS_BUILD = $(LIBDIR)/security/cacerts +ifndef OPENJDK + BLACKLIST_SRC = $(CLOSED_SHARE_SRC)/lib/security/blacklist + BLACKLIST_BUILD = $(LIBDIR)/security/blacklist +endif + FILES_class = $(FILES_java:%.java=$(CLASSBINDIR)/%.class) # @@ -69,7 +74,11 @@ # include $(BUILDDIR)/common/Rules.gmk +ifdef OPENJDK build: properties policy cacerts +else +build: properties policy cacerts blacklist +endif install: all @@ -79,6 +88,8 @@ cacerts: classes $(CACERTS_BUILD) +blacklist: classes $(BLACKLIST_BUILD) + $(PROPS_BUILD): $(PROPS_SRC) $(install-file) @@ -88,9 +99,12 @@ $(CACERTS_BUILD): $(CACERTS_SRC) $(install-file) +$(BLACKLIST_BUILD): $(BLACKLIST_SRC) + $(install-file) + clean clobber:: .delete.classlist $(RM) -r $(CLASSBINDIR)/java/security - $(RM) $(PROPS_BUILD) $(POLICY_BUILD) $(CACERTS_BUILD) + $(RM) $(PROPS_BUILD) $(POLICY_BUILD) $(CACERTS_BUILD) $(BLACKLIST_BUILD) # Additional Rule for building sun.security.util $(CLASSBINDIR)/%.class: $(SHARE_SRC)/sun/%.java diff -r c4a3e3140f7b -r 88db80c8e49c jdk/make/mkdemo/Makefile --- a/jdk/make/mkdemo/Makefile Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/make/mkdemo/Makefile Wed Jul 05 17:18:12 2017 +0200 @@ -46,11 +46,11 @@ $(RM) -r $(DEMODIR)/nbproject $(MKDIR) -p $(DEMODIR) ( $(CD) $(SHARE_SRC)/demo && $(TAR) -cf - \ - `find nbproject $(SCM_DIRS_prune) -o -type f -print` ) | \ + `$(FIND) nbproject $(SCM_DIRS_prune) -o -type f -print` ) | \ ( $(CD) $(DEMODIR) && $(TAR) -xf - ) ifndef OPENJDK ( $(CD) $(CLOSED_SHARE_SRC)/demo && $(TAR) -cf - \ - `find nbproject $(SCM_DIRS_prune) -o -type f -print` ) | \ + `$(FIND) nbproject $(SCM_DIRS_prune) -o -type f -print` ) | \ ( $(CD) $(DEMODIR) && $(TAR) -xf - ) endif diff -r c4a3e3140f7b -r 88db80c8e49c jdk/make/tools/src/build/tools/jarreorder/JarReorder.java --- a/jdk/make/tools/src/build/tools/jarreorder/JarReorder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/make/tools/src/build/tools/jarreorder/JarReorder.java Wed Jul 05 17:18:12 2017 +0200 @@ -28,7 +28,6 @@ * combine with an argument list of files and directories, and * write a list of items to be included in a jar file. */ - package build.tools.jarreorder; import java.io.BufferedReader; @@ -36,74 +35,68 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; +import java.util.Collections; import java.util.HashSet; -import java.util.Vector; import java.io.PrintStream; import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; public class JarReorder { // To deal with output - private static PrintStream out; + private PrintStream out; - private final static boolean useTopDir = false; - - private static void usage() { + private void usage() { String help; help = - "Usage: jar JarReorder [-o ] ...\n" - + " order_list is a file containing names of files to load\n" - + " in order at the end of a jar file.\n" - + " exclude_list is a file containing names of files/directories\n" - + " NOT to be included in a jar file.\n"; - if (useTopDir) - help += - " top_dir is the top of the directory structure to be searched;\n" - + " the contents of the lists and remaining arguments are\n" - + " relative to this.\n"; - help += - "\n" - + "The order_list or exclude_list may be replaced by a \"_\" if no\n" - + "data is to be provided.\n" - + "\n" - + " The remaining arguments are files or directories to be included\n" - + " in a jar file, from which will be excluded thse entries which\n" - + " appear in the exclude list.\n"; + "Usage: jar JarReorder [-o ] ...\n" + + " order_list is a file containing names of files to load\n" + + " in order at the end of a jar file unless\n" + + " excluded in the exclude list.\n" + + " exclude_list is a file containing names of files/directories\n" + + " NOT to be included in a jar file.\n" + + "\n" + + "The order_list or exclude_list may be replaced by a \"-\" if no\n" + + "data is to be provided.\n" + + "\n" + + " The remaining arguments are files or directories to be included\n" + + " in a jar file, from which will be excluded those entries which\n" + + " appear in the exclude list.\n"; System.err.println(help); - System.exit(1); } /* - * Create a list of files to be included in a jar file, such that the - * some the files will appear in a specific order, and allowing certain + * Create the file list to be included in a jar file, such that the + * list will appear in a specific order, and allowing certain * files and directories to be excluded. * - * Command line arguments are + * Command path arguments are * - optional -o outputfile - * - name of a file containing a list of files to be included in a jar file. - * - name of a file containing a list of files (or directories) to be + * - name of a file containing a set of files to be included in a jar file. + * - name of a file containing a set of files (or directories) to be * excluded from the jar file. * - names of files or directories to be searched for files to include * in the jar file. */ public static void main(String[] args) { + JarReorder jr = new JarReorder(); + jr.run(args); + } - HashMap filesExcluded = new HashMap(); - Vector filesIncluded = new Vector(); - int fileArgs; - String topDirName = ""; + private void run(String args[]) { + int arglen = args.length; int argpos = 0; // Look for "-o outputfilename" option - if ( arglen > 0 ) { - if ( arglen >= 2 && args[0].equals("-o") ) { + if (arglen > 0) { + if (arglen >= 2 && args[0].equals("-o")) { try { out = new PrintStream(new FileOutputStream(args[1])); - } catch ( FileNotFoundException e ) { + } catch (FileNotFoundException e) { System.err.println("Error: " + e.getMessage()); e.printStackTrace(System.err); System.exit(1); @@ -118,128 +111,111 @@ out = System.out; } - fileArgs = useTopDir ? 3 : 2; - - if (arglen <= fileArgs) { + // Should be 2 or more args left + if (arglen <= 2) { usage(); + System.exit(1); } - // Read the ordered list of files to be included in rt.jar. - // Read the list of files/directories to be excluded from rt.jar. - - Vector orderList = readListFromFile(args[argpos], true); - Vector excludeList = readListFromFile(args[argpos+1], false); - if (useTopDir) { - topDirName = args[argpos+2]; - if (!topDirName.endsWith(File.separator)) - topDirName = topDirName + File.separator; - } + // Read the ordered set of files to be included in rt.jar. + // Read the set of files/directories to be excluded from rt.jar. + String classListFile = args[argpos]; + String excludeListFile = args[argpos + 1]; + argpos += 2; + arglen -= 2; - // Copy these lists into filesExcluded so that these files will be excluded - // from the file list. (The orderList files will be appended later.) + // Create 2 lists and a set of processed files + List orderList = readListFromFile(classListFile, true); + List excludeList = readListFromFile(excludeListFile, false); + Set processed = new HashSet(); - for (int i = 0; i < orderList.size(); ++i) { - String s = (String) orderList.elementAt(i); - filesExcluded.put(s, s); - } - for (int i = 0; i < excludeList.size(); ++i) { - String s = (String) excludeList.elementAt(i); - filesExcluded.put(s, s); - } + // Create set of all files and directories excluded, then expand + // that list completely + Set excludeSet = new HashSet(excludeList); + Set allFilesExcluded = expand(null, excludeSet, processed); + + // Indicate all these have been processed, orderList too, kept to end. + processed.addAll(orderList); // The remaining arguments are names of files/directories to be included // in the jar file. - - String[] files = new String[arglen - fileArgs]; - for (int i = fileArgs; i < arglen; ++i) { - files[i-fileArgs] = args[argpos+i]; - filesExcluded.put(args[argpos+i], args[argpos+i]); + Set inputSet = new HashSet(); + for (int i = 0; i < arglen; ++i) { + String name = args[argpos + i]; + name = cleanPath(new File(name)); + if ( name != null && name.length() > 0 && !inputSet.contains(name) ) { + inputSet.add(name); + } } - // Expand file/directory list to file list excluding those - // read from the class list. + // Expand file/directory input so we get a complete set (except ordered) + // Should be everything not excluded and not in order list. + Set allFilesIncluded = expand(null, inputSet, processed); - if (useTopDir) - expand(new File(topDirName), files, filesIncluded, filesExcluded, topDirName); - else - expand(null, files, filesIncluded, filesExcluded, null); + // Create simple sorted list so we can add ordered items at end. + List allFiles = new ArrayList(allFilesIncluded); + Collections.sort(allFiles); - // Now add the ordered list to the end of the expanded list. + // Now add the ordered set to the end of the list. // Add in REVERSE ORDER, so that the first element is closest to // the end (and the index). - - HashSet excludeSet = new HashSet(excludeList); for (int i = orderList.size() - 1; i >= 0; --i) { - String s = (String) orderList.elementAt(i); - if (excludeSet.contains(s)) { - System.err.println("Included file " + s + " is also excluded, skipping."); - continue; + String s = orderList.get(i); + if (allFilesExcluded.contains(s)) { + System.err.println("Included order file " + s + + " is also excluded, skipping."); + } else if (new File(s).exists()) { + allFiles.add(s); + } else { + System.err.println("Included order file " + s + + " missing, skipping."); } - if (new File(topDirName + s).exists()) - filesIncluded.addElement(s); - else - System.err.println("Included file "+s+" missing, skipping."); } - // Print results. - - for (int i = 0; i < filesIncluded.size(); ++i) { - if (useTopDir) { - out.print("-C "); - out.print(topDirName); - out.print(" "); - } - out.println((String)filesIncluded.elementAt(i)); + // Print final results. + for (String str : allFiles) { + out.println(str); } - out.flush(); out.close(); } - /* - * Read a file containing a list of files into a Vector. + * Read a file containing a list of files and directories into a List. */ - private static Vector readListFromFile(String fileName, - boolean addClassSuffix) { + private List readListFromFile(String fileName, + boolean addClassSuffix) { BufferedReader br = null; - Vector v = new Vector(2000); - - if ("-".equals(fileName)) - return v; - + List list = new ArrayList(); + // If you see "-" for the name, just assume nothing was provided. + if ("-".equals(fileName)) { + return list; + } try { br = new BufferedReader(new FileReader(fileName)); - - // Read the input file a line at a time. # in column 1 is a comment. - + // Read the input file a path at a time. # in column 1 is a comment. while (true) { - String line = null; - line = br.readLine(); - - if (line == null) + String path = br.readLine(); + if (path == null) { break; - - if (line.length() == 0 || - line.charAt(0) == '#') + } + // Look for comments + path = path.trim(); + if (path.length() == 0 + || path.charAt(0) == '#') { continue; - - // Convert forward or back slashes to the type expected for - // the current platform. - - if (File.separatorChar == '/') - line = line.replace('\\', '/'); - else - line = line.replace('/', '\\'); - - line = line.trim(); - if (addClassSuffix) { - if (!line.endsWith(".class")) { - line = line + ".class"; - } + } + // Add trailing .class if necessary + if (addClassSuffix && !path.endsWith(".class")) { + path = path + ".class"; } - v.addElement(line); + // Normalize the path + path = cleanPath(new File(path)); + // Add to list + if (path != null && path.length() > 0 && !list.contains(path)) { + list.add(path); + } } br.close(); } catch (FileNotFoundException e) { @@ -249,68 +225,89 @@ e.printStackTrace(); System.exit(2); } - return v; + return list; } - /* - * Expands list of files to process into full list of all files that + * Expands inputSet (files or dirs) into full set of all files that * can be found by recursively descending directories. + * @param dir root directory + * @param inputSet set of files or dirs to look into + * @param processed files or dirs already processed + * @return set of files */ - private static void expand(File dir, String[] files, - Vector includedFiles, HashMap excludedFiles, - String topDirName) { - if (files == null) { - return; + private Set expand(File dir, + Set inputSet, + Set processed) { + Set includedFiles = new HashSet(); + if (inputSet.isEmpty()) { + return includedFiles; } - for (int i = 0; i < files.length; i++) { - File f = (dir == null) ? new File(files[i]) - : new File(dir, files[i]); - if (f.isFile()) { - String filePath = f.getPath(); - - if (useTopDir) { - if (filePath.startsWith(topDirName)) - filePath = filePath.substring(topDirName.length()); + for (String name : inputSet) { + // Depending on start location + File f = (dir == null) ? new File(name) + : new File(dir, name); + // Normalized path to use + String path = cleanPath(f); + if (path != null && path.length() > 0 + && !processed.contains(path)) { + if (f.isFile()) { + // Not in the excludeList, add it to both lists + includedFiles.add(path); + processed.add(path); + } else if (f.isDirectory()) { + // Add the directory entries + String[] dirList = f.list(); + Set dirInputSet = new HashSet(); + for (String x : dirList) { + dirInputSet.add(x); + } + // Process all entries in this directory + Set subList = expand(f, dirInputSet, processed); + includedFiles.addAll(subList); + processed.add(path); } - - if (filePath.length() >= 2 && - filePath.charAt(0) == '.' && - filePath.charAt(1) == File.separatorChar) - filePath = filePath.substring(2); - - if (!excludedFiles.containsKey(filePath)) { - excludedFiles.put(filePath, filePath); - includedFiles.addElement(filePath); - } - } else if (f.isDirectory()) { - String dirPath = f.getPath(); - dirPath = (dirPath.endsWith(File.separator)) ? dirPath : - (dirPath + File.separator); - - if (useTopDir) { - if (dirPath.startsWith(topDirName)) - dirPath = dirPath.substring(topDirName.length()); - } - - if (dirPath.length() >= 2 && - dirPath.charAt(0) == '.' && - dirPath.charAt(1) == File.separatorChar) - dirPath = dirPath.substring(2); - - if (!excludedFiles.containsKey(dirPath)) { - - // Sort the directory list so that entries in the jar file - // are in a repeatable order. The order itself is not particularly - // important. [File.list() is unpredictable.] - - String[] dirList = f.list(); - Arrays.sort(dirList); - expand(f, dirList, includedFiles, excludedFiles, topDirName); - } - } else { - System.err.println("Error accessing: " + f.getPath()); } } + return includedFiles; } + + private String cleanPath(File f) { + String path = f.getPath(); + if (f.isFile()) { + path = cleanFilePath(path); + } else if (f.isDirectory()) { + path = cleanDirPath(path); + } else { + System.err.println("WARNING: Path does not exist as file or directory: " + path); + path = null; + } + return path; + } + + private String cleanFilePath(String path) { + // Remove leading and trailing whitespace + path = path.trim(); + // Make all / and \ chars one + if (File.separatorChar == '/') { + path = path.replace('\\', '/'); + } else { + path = path.replace('/', '\\'); + } + // Remove leading ./ + if (path.startsWith("." + File.separator)) { + path = path.substring(2); + } + return path; + } + + private String cleanDirPath(String path) { + path = cleanFilePath(path); + // Make sure it ends with a file separator + if (!path.endsWith(File.separator)) { + path = path + File.separator; + } + return path; + } + } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/bin/emessages.h --- a/jdk/src/share/bin/emessages.h Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/bin/emessages.h Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ #define JVM_ERROR1 "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR #define JVM_ERROR2 "Error: Could not detach main thread.\n" JNI_ERROR -#define JVM_ERROR3 "Error: SPARC V8 processor detected; Server compiler requires V9 or better.\nUse Client compiler on V8 processors.\nCould not create the Java virtual machine." +#define JVM_ERROR3 "Error: SPARC V8 processor detected; Required V9 processors or better.\nUse JDK5 client compiler for V8 processors.\n" JVM_ERROR1 #define JAR_ERROR1 "Error: Failed to load Main-Class manifest attribute from\n%s\n%s" #define JAR_ERROR2 "Error: Unable to access jarfile %s" @@ -69,7 +69,8 @@ #define CFG_ERROR5 "Error: Could not determine application home." #define CFG_ERROR6 "Error: could not open `%s'" #define CFG_ERROR7 "Error: no known VMs. (check for corrupt jvm.cfg file)" -#define CFG_ERROR8 "Error: no `%s' JVM at `%s'." +#define CFG_ERROR8 "Error: missing `%s' JVM at `%s'.\nPlease install or use the JRE or JDK that contains these missing components." +#define CFG_ERROR9 "Error: could not determine JVM type." #define SPC_ERROR1 "Error: Syntax error in version specification \"%s\"" diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/bin/java.c --- a/jdk/src/share/bin/java.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/bin/java.c Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -192,8 +192,8 @@ int ret; InvocationFunctions ifn; jlong start, end; - char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN]; - char ** original_argv = argv; + char jvmpath[MAXPATHLEN]; + char jrepath[MAXPATHLEN]; _fVersion = fullversion; _dVersion = dotversion; @@ -225,14 +225,17 @@ */ SelectVersion(argc, argv, &main_class); - /* copy original argv */ - JLI_TraceLauncher("Command line Args:\n"); - original_argv = (JLI_CopyArgs(argc, (const char**)argv)); + if (JLI_IsTraceLauncher()) { + int i; + printf("Command line args:\n"); + for (i = 0; i < argc ; i++) { + printf("argv[%d] = %s\n", i, argv[i]); + } + } CreateExecutionEnvironment(&argc, &argv, jrepath, sizeof(jrepath), - jvmpath, sizeof(jvmpath), - original_argv); + jvmpath, sizeof(jvmpath)); ifn.CreateJavaVM = 0; ifn.GetDefaultJavaVMInitArgs = 0; @@ -301,22 +304,43 @@ return ContinueInNewThread(&ifn, argc, argv, jarfile, classname, ret); } +/* + * Always detach the main thread so that it appears to have ended when + * the application's main method exits. This will invoke the + * uncaught exception handler machinery if main threw an + * exception. An uncaught exception handler cannot change the + * launcher's return code except by calling System.exit. + * + * Wait for all non-daemon threads to end, then destroy the VM. + * This will actually create a trivial new Java waiter thread + * named "DestroyJavaVM", but this will be seen as a different + * thread from the one that executed main, even though they are + * the same C thread. This allows mainThread.join() and + * mainThread.isAlive() to work as expected. + */ +#define LEAVE() \ + if ((*vm)->DetachCurrentThread(vm) != 0) { \ + JLI_ReportErrorMessage(JVM_ERROR2); \ + ret = 1; \ + } \ + (*vm)->DestroyJavaVM(vm); \ + return ret \ #define CHECK_EXCEPTION_NULL_LEAVE(e) \ if ((*env)->ExceptionOccurred(env)) { \ JLI_ReportExceptionDescription(env); \ - goto leave; \ + LEAVE(); \ } \ if ((e) == NULL) { \ JLI_ReportErrorMessage(JNI_ERROR); \ - goto leave; \ + LEAVE(); \ } #define CHECK_EXCEPTION_LEAVE(rv) \ if ((*env)->ExceptionOccurred(env)) { \ JLI_ReportExceptionDescription(env); \ ret = (rv); \ - goto leave; \ + LEAVE(); \ } int JNICALL @@ -349,8 +373,7 @@ PrintJavaVersion(env, showVersion); CHECK_EXCEPTION_LEAVE(0); if (printVersion) { - ret = 0; - goto leave; + LEAVE(); } } @@ -358,7 +381,7 @@ if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) { PrintUsage(env, printXUsage); CHECK_EXCEPTION_LEAVE(1); - goto leave; + LEAVE(); } FreeKnownVMs(); /* after last possible PrintUsage() */ @@ -430,30 +453,7 @@ * System.exit) will be non-zero if main threw an exception. */ ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; - -leave: - /* - * Always detach the main thread so that it appears to have ended when - * the application's main method exits. This will invoke the - * uncaught exception handler machinery if main threw an - * exception. An uncaught exception handler cannot change the - * launcher's return code except by calling System.exit. - */ - if ((*vm)->DetachCurrentThread(vm) != 0) { - JLI_ReportErrorMessage(JVM_ERROR2); - ret = 1; - } - /* - * Wait for all non-daemon threads to end, then destroy the VM. - * This will actually create a trivial new Java waiter thread - * named "DestroyJavaVM", but this will be seen as a different - * thread from the one that executed main, even though they are - * the same C thread. This allows mainThread.join() and - * mainThread.isAlive() to work as expected. - */ - (*vm)->DestroyJavaVM(vm); - - return ret; + LEAVE(); } /* @@ -1076,15 +1076,17 @@ if (--argc >= 0) { if (jarflag) { *pjarfile = *argv++; - *pclassname = 0; + *pclassname = NULL; } else { - *pjarfile = 0; + *pjarfile = NULL; *pclassname = *argv++; } *pargc = argc; *pargv = argv; } - + if (*pjarfile == NULL && *pclassname == NULL) { + *pret = 1; + } return JNI_TRUE; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/bin/java.h --- a/jdk/src/share/bin/java.h Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/bin/java.h Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,13 +114,19 @@ #define GetArch() GetArchPath(CURRENT_DATA_MODEL) -void CreateExecutionEnvironment(int *_argc, - char ***_argv, - char jrepath[], - jint so_jrepath, - char jvmpath[], - jint so_jvmpath, - char **original_argv); +/* + * Different platforms will implement this, here + * pargc is a pointer to the original argc, + * pargv is a pointer to the original argv, + * jrepath is an accessible path to the jre as determined by the call + * so_jrepath is the length of the buffer jrepath + * jvmpath is an accessible path to the jvm as determined by the call + * so_jvmpath is the length of the buffer jvmpath + */ +void CreateExecutionEnvironment(int *argc, char ***argv, + char *jrepath, jint so_jrepath, + char *jvmpath, jint so_jvmpath); + /* Reports an error message to stderr or a window as appropriate. */ void JLI_ReportErrorMessage(const char * message, ...); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/bin/jli_util.c --- a/jdk/src/share/bin/jli_util.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/bin/jli_util.c Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,23 +85,6 @@ } /* - * Makes a copy of arguments - */ -char** -JLI_CopyArgs(int argc, const char **iargv) -{ - int i; - char** oargv = (char**)JLI_MemAlloc(sizeof(char*)*(argc+1)); - for (i = 0 ; i < argc+1 ; i++) { - oargv[i] = (iargv[i] == NULL) ? NULL : JLI_StringDup(iargv[i]); - if (iargv[i] != NULL && JLI_IsTraceLauncher() == JNI_TRUE) { - printf("\targv[%d] = '%s'\n",i,iargv[i]); - } - } - return oargv; -} - -/* * debug helpers we use */ static jboolean _launcher_debug = JNI_FALSE; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/bin/jli_util.h --- a/jdk/src/share/bin/jli_util.h Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/bin/jli_util.h Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ void *JLI_MemRealloc(void *ptr, size_t size); char *JLI_StringDup(const char *s1); void JLI_MemFree(void *ptr); -char **JLI_CopyArgs(int argc, const char **iargv); int JLI_StrCCmp(const char *s1, const char* s2); @@ -56,10 +55,12 @@ #include #define JLI_StrCaseCmp(p1, p2) stricmp((p1), (p2)) #define JLI_StrNCaseCmp(p1, p2, p3) strnicmp((p1), (p2), (p3)) +#define JLI_Snprintf _snprintf #else #include #define JLI_StrCaseCmp(p1, p2) strcasecmp((p1), (p2)) #define JLI_StrNCaseCmp(p1, p2, p3) strncasecmp((p1), (p2), (p3)) +#define JLI_Snprintf snprintf #endif /* _WIN32 */ /* diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/com/sun/beans/finder/InstanceFinder.java --- a/jdk/src/share/classes/com/sun/beans/finder/InstanceFinder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/com/sun/beans/finder/InstanceFinder.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ private final Class type; private final boolean allow; private final String suffix; - private String[] packages; + private volatile String[] packages; InstanceFinder(Class type, boolean allow, String suffix, String... packages) { this.type = type; @@ -49,9 +49,7 @@ } public String[] getPackages() { - return (this.packages.length > 0) - ? this.packages.clone() - : this.packages; + return this.packages.clone(); } public void setPackages(String... packages) { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java --- a/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,7 @@ * @throws NoSuchMethodException if method is not accessible or is not found * in specified superclass or interface */ - private static Method findAccessibleMethod(Method method) throws NoSuchMethodException { + public static Method findAccessibleMethod(Method method) throws NoSuchMethodException { Class type = method.getDeclaringClass(); if (Modifier.isPublic(type.getModifiers())) { return method; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/com/sun/beans/finder/PersistenceDelegateFinder.java --- a/jdk/src/share/classes/com/sun/beans/finder/PersistenceDelegateFinder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/com/sun/beans/finder/PersistenceDelegateFinder.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,17 +47,22 @@ } public void register(Class type, PersistenceDelegate delegate) { - if (delegate != null) { - this.registry.put(type, delegate); - } - else { - this.registry.remove(type); + synchronized (this.registry) { + if (delegate != null) { + this.registry.put(type, delegate); + } + else { + this.registry.remove(type); + } } } @Override public PersistenceDelegate find(Class type) { - PersistenceDelegate delegate = this.registry.get(type); + PersistenceDelegate delegate; + synchronized (this.registry) { + delegate = this.registry.get(type); + } return (delegate != null) ? delegate : super.find(type); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/com/sun/beans/finder/PropertyEditorFinder.java --- a/jdk/src/share/classes/com/sun/beans/finder/PropertyEditorFinder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/com/sun/beans/finder/PropertyEditorFinder.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,12 +64,18 @@ } public void register(Class type, Class editor) { - this.registry.put(type, editor); + synchronized (this.registry) { + this.registry.put(type, editor); + } } @Override public PropertyEditor find(Class type) { - PropertyEditor editor = instantiate(this.registry.get(type), null); + Class predefined; + synchronized (this.registry) { + predefined = this.registry.get(type); + } + PropertyEditor editor = instantiate(predefined, null); if (editor == null) { editor = super.find(type); if ((editor == null) && (null != type.getEnumConstants())) { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java --- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java Wed Jul 05 17:18:12 2017 +0200 @@ -1440,10 +1440,6 @@ } } - public Insets getBorderInsets(Component c) { - return getBorderInsets(c, null); - } - public Insets getBorderInsets(Component c, Insets i) { SynthContext context = getContext(c); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java --- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -271,7 +271,9 @@ } public void uninstallUI(JComponent c) { - getFileChooser().removeAll(); + c.removePropertyChangeListener(filterComboBoxModel); + approveButton.removeActionListener(getApproveSelectionAction()); + filenameTextField.removeActionListener(getApproveSelectionAction()); super.uninstallUI(c); } @@ -515,6 +517,7 @@ public void uninstallComponents(JFileChooser fc) { fc.removeAll(); + bottomPanel = null; if (filterComboBoxModel != null) { fc.removePropertyChangeListener(filterComboBoxModel); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/awt/EventDispatchThread.java --- a/jdk/src/share/classes/java/awt/EventDispatchThread.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/awt/EventDispatchThread.java Wed Jul 05 17:18:12 2017 +0200 @@ -61,85 +61,43 @@ * @since 1.1 */ class EventDispatchThread extends Thread { + private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread"); private EventQueue theQueue; private boolean doDispatch = true; + private boolean threadDeathCaught = false; + private static final int ANY_EVENT = -1; private Vector eventFilters = new Vector(); - // used in handleException - private int modalFiltersCount = 0; EventDispatchThread(ThreadGroup group, String name, EventQueue queue) { super(group, name); - theQueue = queue; + setEventQueue(queue); } - void stopDispatchingImpl(boolean wait) { - // Note: We stop dispatching via a flag rather than using - // Thread.interrupt() because we can't guarantee that the wait() - // we interrupt will be EventQueue.getNextEvent()'s. -fredx 8-11-98 - - StopDispatchEvent stopEvent = new StopDispatchEvent(); - - // wait for the dispatcher to complete - if (Thread.currentThread() != this) { - - // fix 4122683, 4128923 - // Post an empty event to ensure getNextEvent is unblocked - // - // We have to use postEventPrivate instead of postEvent because - // EventQueue.pop calls EventDispatchThread.stopDispatching. - // Calling SunToolkit.flushPendingEvents in this case could - // lead to deadlock. - theQueue.postEventPrivate(stopEvent); - - if (wait) { - try { - join(); - } catch(InterruptedException e) { - } - } - } else { - stopEvent.dispatch(); - } - - theQueue.detachDispatchThread(this, false); - } - + /* + * Must be called on EDT only, that's why no synchronization + */ public void stopDispatching() { - stopDispatchingImpl(true); - } - - public void stopDispatchingLater() { - stopDispatchingImpl(false); - } - - class StopDispatchEvent extends AWTEvent implements ActiveEvent { - /* - * serialVersionUID - */ - static final long serialVersionUID = -3692158172100730735L; - - public StopDispatchEvent() { - super(EventDispatchThread.this,0); - } - - public void dispatch() { - doDispatch = false; - } + doDispatch = false; } public void run() { - try { - pumpEvents(new Conditional() { - public boolean evaluate() { - return true; + while (true) { + try { + pumpEvents(new Conditional() { + public boolean evaluate() { + return true; + } + }); + } finally { + EventQueue eq = getEventQueue(); + if (eq.detachDispatchThread(this) || threadDeathCaught) { + break; } - }); - } finally { - theQueue.detachDispatchThread(this, true); + } } } @@ -190,7 +148,6 @@ } } eventFilters.add(k, filter); - modalFiltersCount++; } else { eventFilters.add(filter); } @@ -200,28 +157,25 @@ void removeEventFilter(EventFilter filter) { synchronized (eventFilters) { - if (eventFilters.contains(filter)) { - if (filter instanceof ModalEventFilter) { - modalFiltersCount--; - } - eventFilters.remove(filter); - } + eventFilters.remove(filter); } } boolean pumpOneEventForFilters(int id) { + AWTEvent event = null; + boolean eventOK = false; try { - AWTEvent event; - boolean eventOK; - EventQueueDelegate.Delegate delegate = - EventQueueDelegate.getDelegate(); + EventQueue eq = null; + EventQueueDelegate.Delegate delegate = null; do { + // EventQueue may change during the dispatching + eq = getEventQueue(); + delegate = EventQueueDelegate.getDelegate(); + if (delegate != null && id == ANY_EVENT) { - event = delegate.getNextEvent(theQueue); + event = delegate.getNextEvent(eq); } else { - event = (id == ANY_EVENT) - ? theQueue.getNextEvent() - : theQueue.getNextEvent(id); + event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id); } eventOK = true; @@ -252,13 +206,15 @@ if (delegate != null) { handle = delegate.beforeDispatch(event); } - theQueue.dispatchEvent(event); + eq.dispatchEvent(event); if (delegate != null) { delegate.afterDispatch(event, handle); } + return true; } catch (ThreadDeath death) { + threadDeathCaught = true; return false; } @@ -267,12 +223,10 @@ // Threads in the AppContext } - // Can get and throw only unchecked exceptions - catch (RuntimeException e) { - processException(e); - } catch (Error e) { + catch (Throwable e) { processException(e); } + return true; } @@ -281,14 +235,14 @@ eventLog.fine("Processing exception: " + e); } getUncaughtExceptionHandler().uncaughtException(this, e); - // don't rethrow the exception to avoid EDT recreation } - boolean isDispatching(EventQueue eq) { - return theQueue.equals(eq); + public synchronized EventQueue getEventQueue() { + return theQueue; } - - EventQueue getEventQueue() { return theQueue; } + public synchronized void setEventQueue(EventQueue eq) { + theQueue = eq; + } private static class HierarchyEventFilter implements EventFilter { private Component modalComponent; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/awt/EventQueue.java --- a/jdk/src/share/classes/java/awt/EventQueue.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/awt/EventQueue.java Wed Jul 05 17:18:12 2017 +0200 @@ -138,6 +138,15 @@ private final Lock pushPopLock; private final Condition pushPopCond; + /* + * Dummy runnable to wake up EDT from getNextEvent() after + push/pop is performed + */ + private final static Runnable dummyRunnable = new Runnable() { + public void run() { + } + }; + private EventDispatchThread dispatchThread; private final ThreadGroup threadGroup = @@ -219,22 +228,22 @@ * @param theEvent an instance of java.awt.AWTEvent, * or a subclass of it */ - final void postEventPrivate(AWTEvent theEvent) { + private final void postEventPrivate(AWTEvent theEvent) { theEvent.isPosted = true; pushPopLock.lock(); try { - if (dispatchThread == null && nextQueue == null) { + if (nextQueue != null) { + // Forward the event to the top of EventQueue stack + nextQueue.postEventPrivate(theEvent); + return; + } + if (dispatchThread == null) { if (theEvent.getSource() == AWTAutoShutdown.getInstance()) { return; } else { initDispatchThread(); } } - if (nextQueue != null) { - // Forward event to top of EventQueue stack. - nextQueue.postEventPrivate(theEvent); - return; - } postEvent(theEvent, getPriority(theEvent)); } finally { pushPopLock.unlock(); @@ -242,29 +251,20 @@ } private static int getPriority(AWTEvent theEvent) { - if (theEvent instanceof PeerEvent && - (((PeerEvent)theEvent).getFlags() & - PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) - { - return ULTIMATE_PRIORITY; + if (theEvent instanceof PeerEvent) { + PeerEvent peerEvent = (PeerEvent)theEvent; + if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) { + return ULTIMATE_PRIORITY; + } + if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) { + return HIGH_PRIORITY; + } + if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) { + return LOW_PRIORITY; + } } - - if (theEvent instanceof PeerEvent && - (((PeerEvent)theEvent).getFlags() & - PeerEvent.PRIORITY_EVENT) != 0) - { - return HIGH_PRIORITY; - } - - if (theEvent instanceof PeerEvent && - (((PeerEvent)theEvent).getFlags() & - PeerEvent.LOW_PRIORITY_EVENT) != 0) - { - return LOW_PRIORITY; - } - int id = theEvent.getID(); - if (id == PaintEvent.PAINT || id == PaintEvent.UPDATE) { + if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) { return LOW_PRIORITY; } return NORM_PRIORITY; @@ -501,16 +501,9 @@ SunToolkit.flushPendingEvents(); pushPopLock.lock(); try { - for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { - if (queues[i].head != null) { - EventQueueItem entry = queues[i].head; - queues[i].head = entry.next; - if (entry.next == null) { - queues[i].tail = null; - } - uncacheEQItem(entry); - return entry.event; - } + AWTEvent event = getNextEventPrivate(); + if (event != null) { + return event; } AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread); pushPopCond.await(); @@ -520,6 +513,24 @@ } while(true); } + /* + * Must be called under the lock. Doesn't call flushPendingEvents() + */ + AWTEvent getNextEventPrivate() throws InterruptedException { + for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { + if (queues[i].head != null) { + EventQueueItem entry = queues[i].head; + queues[i].head = entry.next; + if (entry.next == null) { + queues[i].tail = null; + } + uncacheEQItem(entry); + return entry.event; + } + } + return null; + } + AWTEvent getNextEvent(int id) throws InterruptedException { do { /* @@ -659,7 +670,9 @@ dispatchThread.stopDispatching(); } } else { - System.err.println("unable to dispatch event: " + event); + if (eventLog.isLoggable(PlatformLogger.FINE)) { + eventLog.fine("Unable to dispatch event: " + event); + } } } @@ -761,15 +774,23 @@ pushPopLock.lock(); try { - EventQueue toPush = this; - while (toPush.nextQueue != null) { - toPush = toPush.nextQueue; + EventQueue topQueue = this; + while (topQueue.nextQueue != null) { + topQueue = topQueue.nextQueue; + } + + if ((topQueue.dispatchThread != null) && + (topQueue.dispatchThread.getEventQueue() == this)) + { + newEventQueue.dispatchThread = topQueue.dispatchThread; + topQueue.dispatchThread.setEventQueue(newEventQueue); } // Transfer all events forward to new EventQueue. - while (toPush.peekEvent() != null) { + while (topQueue.peekEvent() != null) { try { - newEventQueue.postEventPrivate(toPush.getNextEvent()); + // Use getNextEventPrivate() as it doesn't call flushPendingEvents() + newEventQueue.postEventPrivate(topQueue.getNextEventPrivate()); } catch (InterruptedException ie) { if (eventLog.isLoggable(PlatformLogger.FINE)) { eventLog.fine("Interrupted push", ie); @@ -777,28 +798,21 @@ } } - newEventQueue.previousQueue = toPush; + // Wake up EDT waiting in getNextEvent(), so it can + // pick up a new EventQueue. Post the waking event before + // topQueue.nextQueue is assigned, otherwise the event would + // go newEventQueue + topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable)); - /* - * Stop the event dispatch thread associated with the currently - * active event queue, so that after the new queue is pushed - * on the top this event dispatch thread won't prevent AWT from - * being automatically shut down. - * Use stopDispatchingLater() to avoid deadlock: stopDispatching() - * waits for the dispatch thread to exit, which in turn waits - * for the lock in EQ.detachDispatchThread(), which is hold by - * this method. - */ - if (toPush.dispatchThread != null) { - toPush.dispatchThread.stopDispatchingLater(); + newEventQueue.previousQueue = topQueue; + topQueue.nextQueue = newEventQueue; + + AppContext appContext = AppContext.getAppContext(); + if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) { + appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue); } - toPush.nextQueue = newEventQueue; - - AppContext appContext = AppContext.getAppContext(); - if (appContext.get(AppContext.EVENT_QUEUE_KEY) == toPush) { - appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue); - } + pushPopCond.signalAll(); } finally { pushPopLock.unlock(); } @@ -822,44 +836,51 @@ eventLog.fine("EventQueue.pop(" + this + ")"); } - EventDispatchThread dt = null; pushPopLock.lock(); try { - EventQueue toPop = this; - while (toPop.nextQueue != null) { - toPop = toPop.nextQueue; + EventQueue topQueue = this; + while (topQueue.nextQueue != null) { + topQueue = topQueue.nextQueue; } - EventQueue prev = toPop.previousQueue; - if (prev == null) { + EventQueue prevQueue = topQueue.previousQueue; + if (prevQueue == null) { throw new EmptyStackException(); } - toPop.previousQueue = null; + + topQueue.previousQueue = null; + prevQueue.nextQueue = null; // Transfer all events back to previous EventQueue. - prev.nextQueue = null; - while (toPop.peekEvent() != null) { + while (topQueue.peekEvent() != null) { try { - prev.postEventPrivate(toPop.getNextEvent()); + prevQueue.postEventPrivate(topQueue.getNextEventPrivate()); } catch (InterruptedException ie) { if (eventLog.isLoggable(PlatformLogger.FINE)) { eventLog.fine("Interrupted pop", ie); } } } - AppContext appContext = AppContext.getAppContext(); - if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) { - appContext.put(AppContext.EVENT_QUEUE_KEY, prev); + + if ((topQueue.dispatchThread != null) && + (topQueue.dispatchThread.getEventQueue() == this)) + { + prevQueue.dispatchThread = topQueue.dispatchThread; + topQueue.dispatchThread.setEventQueue(prevQueue); } - dt = toPop.dispatchThread; + AppContext appContext = AppContext.getAppContext(); + if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) { + appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue); + } + + // Wake up EDT waiting in getNextEvent(), so it can + // pick up a new EventQueue + topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable)); + + pushPopCond.signalAll(); } finally { pushPopLock.unlock(); } - - if (dt != null) { - dt.stopDispatching(); // Must be done outside synchronized - // block to avoid possible deadlock - } } /** @@ -907,9 +928,9 @@ try { AppContext appContext = AppContext.getAppContext(); if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) { - dispatchThread = (EventDispatchThread) - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { + dispatchThread = AccessController.doPrivileged( + new PrivilegedAction() { + public EventDispatchThread run() { EventDispatchThread t = new EventDispatchThread(threadGroup, name, @@ -919,7 +940,8 @@ t.setDaemon(false); return t; } - }); + } + ); AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread); dispatchThread.start(); } @@ -928,7 +950,7 @@ } } - final void detachDispatchThread(EventDispatchThread edt, boolean restart) { + final boolean detachDispatchThread(EventDispatchThread edt) { /* * This synchronized block is to secure that the event dispatch * thread won't die in the middle of posting a new event to the @@ -939,26 +961,21 @@ */ pushPopLock.lock(); try { - EventDispatchThread oldDispatchThread = dispatchThread; - if (dispatchThread == edt) { - dispatchThread = null; - } - if (restart) { + if (edt == dispatchThread) { /* - * Event dispatch thread dies in case of an uncaught exception. - * A new event dispatch thread for this queue will be started - * only if a new event is posted to it. In case if no more - * events are posted after this thread died all events that - * currently are in the queue will never be dispatched. + * Don't detach the thread if any events are pending. Not + * sure if it's a possible scenario, though. * * Fix for 4648733. Check both the associated java event * queue and the PostEventQueue. */ if ((peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) { - initDispatchThread(); + return false; } - AWTAutoShutdown.getInstance().notifyThreadFree(oldDispatchThread); + dispatchThread = null; } + AWTAutoShutdown.getInstance().notifyThreadFree(edt); + return true; } finally { pushPopLock.unlock(); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/beans/Encoder.java --- a/jdk/src/share/classes/java/beans/Encoder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/beans/Encoder.java Wed Jul 05 17:18:12 2017 +0200 @@ -194,13 +194,8 @@ * @see java.beans.BeanInfo#getBeanDescriptor */ public PersistenceDelegate getPersistenceDelegate(Class type) { - synchronized (this.finder) { - PersistenceDelegate pd = this.finder.find(type); - if (pd != null) { - return pd; - } - } - return MetaData.getPersistenceDelegate(type); + PersistenceDelegate pd = this.finder.find(type); + return (pd != null) ? pd : MetaData.getPersistenceDelegate(type); } /** @@ -214,9 +209,7 @@ * @see java.beans.BeanInfo#getBeanDescriptor */ public void setPersistenceDelegate(Class type, PersistenceDelegate delegate) { - synchronized (this.finder) { - this.finder.register(type, delegate); - } + this.finder.register(type, delegate); } /** diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/beans/EventSetDescriptor.java --- a/jdk/src/share/classes/java/beans/EventSetDescriptor.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/beans/EventSetDescriptor.java Wed Jul 05 17:18:12 2017 +0200 @@ -27,6 +27,7 @@ import java.lang.ref.Reference; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; /** * An EventSetDescriptor describes a group of events that a given Java @@ -175,10 +176,8 @@ setRemoveListenerMethod(getMethod(sourceClass, removeListenerMethodName, 1)); // Be more forgiving of not finding the getListener method. - Method method = Introspector.findMethod(sourceClass, - getListenerMethodName, 0); - if (method != null) { - setGetListenerMethod(method); + if (getListenerMethodName != null) { + setGetListenerMethod(Introspector.findInstanceMethod(sourceClass, getListenerMethodName)); } } @@ -188,7 +187,7 @@ return null; } Method method = Introspector.findMethod(cls, name, args); - if (method == null) { + if ((method == null) || Modifier.isStatic(method.getModifiers())) { throw new IntrospectionException("Method not found: " + name + " on class " + cls.getName()); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/beans/IndexedPropertyDescriptor.java --- a/jdk/src/share/classes/java/beans/IndexedPropertyDescriptor.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/beans/IndexedPropertyDescriptor.java Wed Jul 05 17:18:12 2017 +0200 @@ -189,16 +189,11 @@ indexedReadMethodName = Introspector.GET_PREFIX + getBaseName(); } } - - Class[] args = { int.class }; - - indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, - 1, args); + indexedReadMethod = Introspector.findInstanceMethod(cls, indexedReadMethodName, int.class); if (indexedReadMethod == null) { // no "is" method, so look for a "get" method. indexedReadMethodName = Introspector.GET_PREFIX + getBaseName(); - indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, - 1, args); + indexedReadMethod = Introspector.findInstanceMethod(cls, indexedReadMethodName, int.class); } setIndexedReadMethod0(indexedReadMethod); } @@ -270,8 +265,7 @@ if (indexedWriteMethodName == null) { indexedWriteMethodName = Introspector.SET_PREFIX + getBaseName(); } - indexedWriteMethod = Introspector.findMethod(cls, indexedWriteMethodName, - 2, (type == null) ? null : new Class[] { int.class, type }); + indexedWriteMethod = Introspector.findInstanceMethod(cls, indexedWriteMethodName, int.class, type); if (indexedWriteMethod != null) { if (!indexedWriteMethod.getReturnType().equals(void.class)) { indexedWriteMethod = null; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/beans/Introspector.java --- a/jdk/src/share/classes/java/beans/Introspector.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/beans/Introspector.java Wed Jul 05 17:18:12 2017 +0200 @@ -28,6 +28,7 @@ import com.sun.beans.WeakCache; import com.sun.beans.finder.BeanInfoFinder; import com.sun.beans.finder.ClassFinder; +import com.sun.beans.finder.MethodFinder; import java.lang.ref.Reference; import java.lang.ref.SoftReference; @@ -157,21 +158,23 @@ if (!ReflectUtil.isPackageAccessible(beanClass)) { return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo(); } + Map, BeanInfo> beanInfoCache; + BeanInfo beanInfo; synchronized (BEANINFO_CACHE) { - Map, BeanInfo> beanInfoCache = - (Map, BeanInfo>) AppContext.getAppContext().get(BEANINFO_CACHE); - + beanInfoCache = (Map, BeanInfo>) AppContext.getAppContext().get(BEANINFO_CACHE); if (beanInfoCache == null) { beanInfoCache = new WeakHashMap, BeanInfo>(); AppContext.getAppContext().put(BEANINFO_CACHE, beanInfoCache); } - BeanInfo beanInfo = beanInfoCache.get(beanClass); - if (beanInfo == null) { - beanInfo = (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo(); + beanInfo = beanInfoCache.get(beanClass); + } + if (beanInfo == null) { + beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo(); + synchronized (BEANINFO_CACHE) { beanInfoCache.put(beanClass, beanInfo); } - return beanInfo; } + return beanInfo; } /** @@ -301,10 +304,7 @@ */ public static String[] getBeanInfoSearchPath() { - BeanInfoFinder finder = getFinder(); - synchronized (finder) { - return finder.getPackages(); - } + return getFinder().getPackages(); } /** @@ -328,10 +328,7 @@ if (sm != null) { sm.checkPropertiesAccess(); } - BeanInfoFinder finder = getFinder(); - synchronized (finder) { - finder.setPackages(path); - } + getFinder().setPackages(path); } @@ -453,10 +450,7 @@ * @return Instance of an explicit BeanInfo class or null if one isn't found. */ private static BeanInfo findExplicitBeanInfo(Class beanClass) { - BeanInfoFinder finder = getFinder(); - synchronized (finder) { - return finder.find(beanClass); - } + return getFinder().find(beanClass); } /** @@ -849,8 +843,8 @@ Method read = result.getReadMethod(); if (read == null && write != null) { - read = findMethod(result.getClass0(), - GET_PREFIX + NameGenerator.capitalize(result.getName()), 0); + read = findInstanceMethod(result.getClass0(), + GET_PREFIX + NameGenerator.capitalize(result.getName())); if (read != null) { try { result.setReadMethod(read); @@ -860,9 +854,9 @@ } } if (write == null && read != null) { - write = findMethod(result.getClass0(), - SET_PREFIX + NameGenerator.capitalize(result.getName()), 1, - new Class[] { FeatureDescriptor.getReturnType(result.getClass0(), read) }); + write = findInstanceMethod(result.getClass0(), + SET_PREFIX + NameGenerator.capitalize(result.getName()), + FeatureDescriptor.getReturnType(result.getClass0(), read)); if (write != null) { try { result.setWriteMethod(write); @@ -1286,90 +1280,27 @@ // Package private support methods. //====================================================================== - /** - * Internal support for finding a target methodName with a given - * parameter list on a given class. - */ - private static Method internalFindMethod(Class start, String methodName, - int argCount, Class args[]) { - // For overriden methods we need to find the most derived version. - // So we start with the given class and walk up the superclass chain. - - Method method = null; - - for (Class cl = start; cl != null; cl = cl.getSuperclass()) { - Method methods[] = getPublicDeclaredMethods(cl); - for (int i = 0; i < methods.length; i++) { - method = methods[i]; - if (method == null) { - continue; + static Method findMethod(Class type, String name, int args) { + for (Method method : type.getMethods()) { + if (method.getName().equals(name) && (args == method.getParameterTypes().length)) { + try { + return MethodFinder.findAccessibleMethod(method); } - - // make sure method signature matches. - Class params[] = FeatureDescriptor.getParameterTypes(start, method); - if (method.getName().equals(methodName) && - params.length == argCount) { - if (args != null) { - boolean different = false; - if (argCount > 0) { - for (int j = 0; j < argCount; j++) { - if (params[j] != args[j]) { - different = true; - continue; - } - } - if (different) { - continue; - } - } - } - return method; + catch (NoSuchMethodException exception) { + // continue search for a method with the specified count of parameters } } } - method = null; - - // Now check any inherited interfaces. This is necessary both when - // the argument class is itself an interface, and when the argument - // class is an abstract class. - Class ifcs[] = start.getInterfaces(); - for (int i = 0 ; i < ifcs.length; i++) { - // Note: The original implementation had both methods calling - // the 3 arg method. This is preserved but perhaps it should - // pass the args array instead of null. - method = internalFindMethod(ifcs[i], methodName, argCount, null); - if (method != null) { - break; - } - } - return method; + return null; } - /** - * Find a target methodName on a given class. - */ - static Method findMethod(Class cls, String methodName, int argCount) { - return findMethod(cls, methodName, argCount, null); - } - - /** - * Find a target methodName with specific parameter list on a given class. - *

- * Used in the contructors of the EventSetDescriptor, - * PropertyDescriptor and the IndexedPropertyDescriptor. - *

- * @param cls The Class object on which to retrieve the method. - * @param methodName Name of the method. - * @param argCount Number of arguments for the desired method. - * @param args Array of argument types for the method. - * @return the method or null if not found - */ - static Method findMethod(Class cls, String methodName, int argCount, - Class args[]) { - if (methodName == null) { + static Method findInstanceMethod(Class type, String name, Class... args) { + try { + return MethodFinder.findInstanceMethod(type, name, args); + } + catch (NoSuchMethodException exception) { return null; } - return internalFindMethod(cls, methodName, argCount, args); } /** diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/beans/MethodDescriptor.java --- a/jdk/src/share/classes/java/beans/MethodDescriptor.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/beans/MethodDescriptor.java Wed Jul 05 17:18:12 2017 +0200 @@ -82,21 +82,21 @@ Method method = getMethod0(); if (method == null) { Class cls = getClass0(); - if (cls != null) { + String name = getName(); + if ((cls != null) && (name != null)) { Class[] params = getParams(); if (params == null) { for (int i = 0; i < 3; i++) { // Find methods for up to 2 params. We are guessing here. // This block should never execute unless the classloader // that loaded the argument classes disappears. - method = Introspector.findMethod(cls, getName(), i, null); + method = Introspector.findMethod(cls, name, i); if (method != null) { break; } } } else { - method = Introspector.findMethod(cls, getName(), - params.length, params); + method = Statement.getMethod(cls, name, params); } setMethod(method); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/beans/PropertyDescriptor.java --- a/jdk/src/share/classes/java/beans/PropertyDescriptor.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/beans/PropertyDescriptor.java Wed Jul 05 17:18:12 2017 +0200 @@ -112,9 +112,7 @@ // If this class or one of its base classes allow PropertyChangeListener, // then we assume that any properties we discover are "bound". // See Introspector.getTargetPropertyInfo() method. - String name = "addPropertyChangeListener"; - Class[] args = {PropertyChangeListener.class}; - this.bound = (null != Introspector.findMethod(beanClass, name, args.length, args)); + this.bound = null != Introspector.findInstanceMethod(beanClass, "addPropertyChangeListener", PropertyChangeListener.class); } /** @@ -225,10 +223,10 @@ // property type is. For booleans, there can be "is" and "get" // methods. If an "is" method exists, this is the official // reader method so look for this one first. - readMethod = Introspector.findMethod(cls, readMethodName, 0); + readMethod = Introspector.findInstanceMethod(cls, readMethodName); if (readMethod == null) { readMethodName = Introspector.GET_PREFIX + getBaseName(); - readMethod = Introspector.findMethod(cls, readMethodName, 0); + readMethod = Introspector.findInstanceMethod(cls, readMethodName); } try { setReadMethod(readMethod); @@ -293,8 +291,7 @@ writeMethodName = Introspector.SET_PREFIX + getBaseName(); } - writeMethod = Introspector.findMethod(cls, writeMethodName, 1, - (type == null) ? null : new Class[] { type }); + writeMethod = Introspector.findInstanceMethod(cls, writeMethodName, type); if (writeMethod != null) { if (!writeMethod.getReturnType().equals(void.class)) { writeMethod = null; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/beans/PropertyEditorManager.java --- a/jdk/src/share/classes/java/beans/PropertyEditorManager.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/beans/PropertyEditorManager.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,10 +81,7 @@ if (sm != null) { sm.checkPropertiesAccess(); } - PropertyEditorFinder finder = getFinder(); - synchronized (finder) { - finder.register(targetType, editorClass); - } + getFinder().register(targetType, editorClass); } /** @@ -95,10 +92,7 @@ * The result is null if no suitable editor can be found. */ public static PropertyEditor findEditor(Class targetType) { - PropertyEditorFinder finder = getFinder(); - synchronized (finder) { - return finder.find(targetType); - } + return getFinder().find(targetType); } /** @@ -110,10 +104,7 @@ * e.g. Sun implementation initially sets to {"sun.beans.editors"}. */ public static String[] getEditorSearchPath() { - PropertyEditorFinder finder = getFinder(); - synchronized (finder) { - return finder.getPackages(); - } + return getFinder().getPackages(); } /** @@ -134,10 +125,7 @@ if (sm != null) { sm.checkPropertiesAccess(); } - PropertyEditorFinder finder = getFinder(); - synchronized (finder) { - finder.setPackages(path); - } + getFinder().setPackages(path); } private static PropertyEditorFinder getFinder() { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/beans/XMLDecoder.java --- a/jdk/src/share/classes/java/beans/XMLDecoder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/beans/XMLDecoder.java Wed Jul 05 17:18:12 2017 +0200 @@ -60,7 +60,7 @@ * * @author Philip Milne */ -public class XMLDecoder { +public class XMLDecoder implements AutoCloseable { private final DocumentHandler handler = new DocumentHandler(); private final InputSource input; private Object owner; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/beans/XMLEncoder.java --- a/jdk/src/share/classes/java/beans/XMLEncoder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/beans/XMLEncoder.java Wed Jul 05 17:18:12 2017 +0200 @@ -204,7 +204,7 @@ * * @author Philip Milne */ -public class XMLEncoder extends Encoder { +public class XMLEncoder extends Encoder implements AutoCloseable { private final CharsetEncoder encoder; private final String charset; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/io/Bits.java --- a/jdk/src/share/classes/java/io/Bits.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/io/Bits.java Wed Jul 05 17:18:12 2017 +0200 @@ -41,51 +41,39 @@ } static char getChar(byte[] b, int off) { - return (char) (((b[off + 1] & 0xFF) << 0) + - ((b[off + 0]) << 8)); + return (char) ((b[off + 1] & 0xFF) + + (b[off] << 8)); } static short getShort(byte[] b, int off) { - return (short) (((b[off + 1] & 0xFF) << 0) + - ((b[off + 0]) << 8)); + return (short) ((b[off + 1] & 0xFF) + + (b[off] << 8)); } static int getInt(byte[] b, int off) { - return ((b[off + 3] & 0xFF) << 0) + - ((b[off + 2] & 0xFF) << 8) + + return ((b[off + 3] & 0xFF) ) + + ((b[off + 2] & 0xFF) << 8) + ((b[off + 1] & 0xFF) << 16) + - ((b[off + 0]) << 24); + ((b[off ] ) << 24); } static float getFloat(byte[] b, int off) { - int i = ((b[off + 3] & 0xFF) << 0) + - ((b[off + 2] & 0xFF) << 8) + - ((b[off + 1] & 0xFF) << 16) + - ((b[off + 0]) << 24); - return Float.intBitsToFloat(i); + return Float.intBitsToFloat(getInt(b, off)); } static long getLong(byte[] b, int off) { - return ((b[off + 7] & 0xFFL) << 0) + - ((b[off + 6] & 0xFFL) << 8) + + return ((b[off + 7] & 0xFFL) ) + + ((b[off + 6] & 0xFFL) << 8) + ((b[off + 5] & 0xFFL) << 16) + ((b[off + 4] & 0xFFL) << 24) + ((b[off + 3] & 0xFFL) << 32) + ((b[off + 2] & 0xFFL) << 40) + ((b[off + 1] & 0xFFL) << 48) + - (((long) b[off + 0]) << 56); + (((long) b[off]) << 56); } static double getDouble(byte[] b, int off) { - long j = ((b[off + 7] & 0xFFL) << 0) + - ((b[off + 6] & 0xFFL) << 8) + - ((b[off + 5] & 0xFFL) << 16) + - ((b[off + 4] & 0xFFL) << 24) + - ((b[off + 3] & 0xFFL) << 32) + - ((b[off + 2] & 0xFFL) << 40) + - ((b[off + 1] & 0xFFL) << 48) + - (((long) b[off + 0]) << 56); - return Double.longBitsToDouble(j); + return Double.longBitsToDouble(getLong(b, off)); } /* @@ -98,50 +86,38 @@ } static void putChar(byte[] b, int off, char val) { - b[off + 1] = (byte) (val >>> 0); - b[off + 0] = (byte) (val >>> 8); + b[off + 1] = (byte) (val ); + b[off ] = (byte) (val >>> 8); } static void putShort(byte[] b, int off, short val) { - b[off + 1] = (byte) (val >>> 0); - b[off + 0] = (byte) (val >>> 8); + b[off + 1] = (byte) (val ); + b[off ] = (byte) (val >>> 8); } static void putInt(byte[] b, int off, int val) { - b[off + 3] = (byte) (val >>> 0); - b[off + 2] = (byte) (val >>> 8); + b[off + 3] = (byte) (val ); + b[off + 2] = (byte) (val >>> 8); b[off + 1] = (byte) (val >>> 16); - b[off + 0] = (byte) (val >>> 24); + b[off ] = (byte) (val >>> 24); } static void putFloat(byte[] b, int off, float val) { - int i = Float.floatToIntBits(val); - b[off + 3] = (byte) (i >>> 0); - b[off + 2] = (byte) (i >>> 8); - b[off + 1] = (byte) (i >>> 16); - b[off + 0] = (byte) (i >>> 24); + putInt(b, off, Float.floatToIntBits(val)); } static void putLong(byte[] b, int off, long val) { - b[off + 7] = (byte) (val >>> 0); - b[off + 6] = (byte) (val >>> 8); + b[off + 7] = (byte) (val ); + b[off + 6] = (byte) (val >>> 8); b[off + 5] = (byte) (val >>> 16); b[off + 4] = (byte) (val >>> 24); b[off + 3] = (byte) (val >>> 32); b[off + 2] = (byte) (val >>> 40); b[off + 1] = (byte) (val >>> 48); - b[off + 0] = (byte) (val >>> 56); + b[off ] = (byte) (val >>> 56); } static void putDouble(byte[] b, int off, double val) { - long j = Double.doubleToLongBits(val); - b[off + 7] = (byte) (j >>> 0); - b[off + 6] = (byte) (j >>> 8); - b[off + 5] = (byte) (j >>> 16); - b[off + 4] = (byte) (j >>> 24); - b[off + 3] = (byte) (j >>> 32); - b[off + 2] = (byte) (j >>> 40); - b[off + 1] = (byte) (j >>> 48); - b[off + 0] = (byte) (j >>> 56); + putLong(b, off, Double.doubleToLongBits(val)); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/io/Closeable.java --- a/jdk/src/share/classes/java/io/Closeable.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/io/Closeable.java Wed Jul 05 17:18:12 2017 +0200 @@ -28,14 +28,14 @@ import java.io.IOException; /** - * A Closeable is a source or destination of data that can be closed. + * A {@code Closeable} is a source or destination of data that can be closed. * The close method is invoked to release resources that the object is * holding (such as open files). * * @since 1.5 */ -public interface Closeable { +public interface Closeable extends AutoCloseable { /** * Closes this stream and releases any system resources associated @@ -45,5 +45,4 @@ * @throws IOException if an I/O error occurs */ public void close() throws IOException; - } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/io/ObjectInput.java --- a/jdk/src/share/classes/java/io/ObjectInput.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/io/ObjectInput.java Wed Jul 05 17:18:12 2017 +0200 @@ -36,7 +36,7 @@ * @see java.io.ObjectInputStream * @since JDK1.1 */ -public interface ObjectInput extends DataInput { +public interface ObjectInput extends DataInput, AutoCloseable { /** * Read and return an object. The class that implements this interface * defines where the object is "read" from. diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/io/ObjectOutput.java --- a/jdk/src/share/classes/java/io/ObjectOutput.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/io/ObjectOutput.java Wed Jul 05 17:18:12 2017 +0200 @@ -36,7 +36,7 @@ * @see java.io.ObjectInputStream * @since JDK1.1 */ -public interface ObjectOutput extends DataOutput { +public interface ObjectOutput extends DataOutput, AutoCloseable { /** * Write an object to the underlying storage or stream. The * class that implements this interface defines how the object is diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/lang/AbstractStringBuilder.java --- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java Wed Jul 05 17:18:12 2017 +0200 @@ -721,20 +721,19 @@ * {@code codePoint} isn't a valid Unicode code point */ public AbstractStringBuilder appendCodePoint(int codePoint) { - if (!Character.isValidCodePoint(codePoint)) { + final int count = this.count; + + if (Character.isBmpCodePoint(codePoint)) { + ensureCapacityInternal(count + 1); + value[count] = (char) codePoint; + this.count = count + 1; + } else if (Character.isValidCodePoint(codePoint)) { + ensureCapacityInternal(count + 2); + Character.toSurrogates(codePoint, value, count); + this.count = count + 2; + } else { throw new IllegalArgumentException(); } - int n = 1; - if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) { - n++; - } - ensureCapacityInternal(count + n); - if (n == 1) { - value[count++] = (char) codePoint; - } else { - Character.toSurrogates(codePoint, value, count); - count += n; - } return this; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/lang/AutoCloseable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/lang/AutoCloseable.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * A resource that must be closed when it is no longer needed. + * + * @author Josh Bloch + * @since 1.7 + */ +public interface AutoCloseable { + /** + * Close this resource, relinquishing any underlying resources. + * This method is invoked automatically by the automatic resource + * management block construct. + * + *

Classes implementing this method are strongly encouraged to + * be declared to throw more specific exceptions (or no exception + * at all, if the close cannot fail). + * + * @throws Exception if this resource cannot be closed + */ + void close() throws Exception; +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/lang/Character.java --- a/jdk/src/share/classes/java/lang/Character.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/lang/Character.java Wed Jul 05 17:18:12 2017 +0200 @@ -24,6 +24,7 @@ */ package java.lang; + import java.util.Arrays; import java.util.Map; import java.util.HashMap; @@ -67,17 +68,16 @@ * definition of the U+n notation in the Unicode * standard.) * - *

The set of characters from U+0000 to U+FFFF is sometimes - * referred to as the Basic Multilingual Plane (BMP). Characters whose code points are greater + *

The set of characters from U+0000 to U+FFFF is + * sometimes referred to as the Basic Multilingual Plane (BMP). + * Characters whose code points are greater * than U+FFFF are called supplementary characters. The Java - * 2 platform uses the UTF-16 representation in char - * arrays and in the String and StringBuffer - * classes. In this representation, supplementary characters are - * represented as a pair of char values, the first from - * the high-surrogates range, (\uD800-\uDBFF), the - * second from the low-surrogates range - * (\uDC00-\uDFFF). + * platform uses the UTF-16 representation in char arrays and + * in the String and StringBuffer classes. In + * this representation, supplementary characters are represented as a pair + * of char values, the first from the high-surrogates + * range, (\uD800-\uDBFF), the second from the + * low-surrogates range (\uDC00-\uDFFF). * *

A char value, therefore, represents Basic * Multilingual Plane (BMP) code points, including the surrogate @@ -115,10 +115,12 @@ * @author Lee Boynton * @author Guy Steele * @author Akira Tanaka + * @author Martin Buchholz + * @author Ulf Zibis * @since 1.0 */ public final -class Character extends Object implements java.io.Serializable, Comparable { +class Character implements java.io.Serializable, Comparable { /** * The minimum radix available for conversion to and from strings. * The constant value of this field is the smallest value permitted @@ -127,10 +129,10 @@ * method, and the toString method of class * Integer. * - * @see java.lang.Character#digit(char, int) - * @see java.lang.Character#forDigit(int, int) - * @see java.lang.Integer#toString(int, int) - * @see java.lang.Integer#valueOf(java.lang.String) + * @see Character#digit(char, int) + * @see Character#forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) */ public static final int MIN_RADIX = 2; @@ -142,10 +144,10 @@ * method, and the toString method of class * Integer. * - * @see java.lang.Character#digit(char, int) - * @see java.lang.Character#forDigit(int, int) - * @see java.lang.Integer#toString(int, int) - * @see java.lang.Integer#valueOf(java.lang.String) + * @see Character#digit(char, int) + * @see Character#forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) */ public static final int MAX_RADIX = 36; @@ -155,7 +157,7 @@ * * @since 1.0.2 */ - public static final char MIN_VALUE = '\u0000'; + public static final char MIN_VALUE = '\u0000'; /** * The constant value of this field is the largest value of type @@ -163,7 +165,7 @@ * * @since 1.0.2 */ - public static final char MAX_VALUE = '\uFFFF'; + public static final char MAX_VALUE = '\uFFFF'; /** * The Class instance representing the primitive type @@ -171,230 +173,201 @@ * * @since 1.1 */ + @SuppressWarnings("unchecked") public static final Class TYPE = Class.getPrimitiveClass("char"); - /* - * Normative general types - */ - - /* - * General character types - */ - - /** - * General category "Cn" in the Unicode specification. - * @since 1.1 - */ - public static final byte - UNASSIGNED = 0; - - /** - * General category "Lu" in the Unicode specification. - * @since 1.1 - */ - public static final byte - UPPERCASE_LETTER = 1; - - /** - * General category "Ll" in the Unicode specification. - * @since 1.1 - */ - public static final byte - LOWERCASE_LETTER = 2; - - /** - * General category "Lt" in the Unicode specification. - * @since 1.1 - */ - public static final byte - TITLECASE_LETTER = 3; - - /** - * General category "Lm" in the Unicode specification. - * @since 1.1 - */ - public static final byte - MODIFIER_LETTER = 4; - - /** - * General category "Lo" in the Unicode specification. - * @since 1.1 - */ - public static final byte - OTHER_LETTER = 5; - - /** - * General category "Mn" in the Unicode specification. - * @since 1.1 - */ - public static final byte - NON_SPACING_MARK = 6; - - /** - * General category "Me" in the Unicode specification. - * @since 1.1 - */ - public static final byte - ENCLOSING_MARK = 7; - - /** - * General category "Mc" in the Unicode specification. - * @since 1.1 - */ - public static final byte - COMBINING_SPACING_MARK = 8; - - /** - * General category "Nd" in the Unicode specification. - * @since 1.1 - */ - public static final byte - DECIMAL_DIGIT_NUMBER = 9; - - /** - * General category "Nl" in the Unicode specification. - * @since 1.1 - */ - public static final byte - LETTER_NUMBER = 10; - - /** - * General category "No" in the Unicode specification. - * @since 1.1 - */ - public static final byte - OTHER_NUMBER = 11; - - /** - * General category "Zs" in the Unicode specification. - * @since 1.1 - */ - public static final byte - SPACE_SEPARATOR = 12; - - /** - * General category "Zl" in the Unicode specification. - * @since 1.1 - */ - public static final byte - LINE_SEPARATOR = 13; - - /** - * General category "Zp" in the Unicode specification. - * @since 1.1 - */ - public static final byte - PARAGRAPH_SEPARATOR = 14; - - /** - * General category "Cc" in the Unicode specification. - * @since 1.1 - */ - public static final byte - CONTROL = 15; - - /** - * General category "Cf" in the Unicode specification. - * @since 1.1 - */ - public static final byte - FORMAT = 16; - - /** - * General category "Co" in the Unicode specification. - * @since 1.1 - */ - public static final byte - PRIVATE_USE = 18; - - /** - * General category "Cs" in the Unicode specification. - * @since 1.1 - */ - public static final byte - SURROGATE = 19; - - /** - * General category "Pd" in the Unicode specification. - * @since 1.1 - */ - public static final byte - DASH_PUNCTUATION = 20; - - /** - * General category "Ps" in the Unicode specification. - * @since 1.1 - */ - public static final byte - START_PUNCTUATION = 21; - - /** - * General category "Pe" in the Unicode specification. - * @since 1.1 - */ - public static final byte - END_PUNCTUATION = 22; - - /** - * General category "Pc" in the Unicode specification. - * @since 1.1 - */ - public static final byte - CONNECTOR_PUNCTUATION = 23; - - /** - * General category "Po" in the Unicode specification. - * @since 1.1 - */ - public static final byte - OTHER_PUNCTUATION = 24; - - /** - * General category "Sm" in the Unicode specification. - * @since 1.1 - */ - public static final byte - MATH_SYMBOL = 25; - - /** - * General category "Sc" in the Unicode specification. - * @since 1.1 - */ - public static final byte - CURRENCY_SYMBOL = 26; - - /** - * General category "Sk" in the Unicode specification. - * @since 1.1 - */ - public static final byte - MODIFIER_SYMBOL = 27; - - /** - * General category "So" in the Unicode specification. - * @since 1.1 - */ - public static final byte - OTHER_SYMBOL = 28; - - /** - * General category "Pi" in the Unicode specification. - * @since 1.4 - */ - public static final byte - INITIAL_QUOTE_PUNCTUATION = 29; - - /** - * General category "Pf" in the Unicode specification. - * @since 1.4 - */ - public static final byte - FINAL_QUOTE_PUNCTUATION = 30; + /* + * Normative general types + */ + + /* + * General character types + */ + + /** + * General category "Cn" in the Unicode specification. + * @since 1.1 + */ + public static final byte UNASSIGNED = 0; + + /** + * General category "Lu" in the Unicode specification. + * @since 1.1 + */ + public static final byte UPPERCASE_LETTER = 1; + + /** + * General category "Ll" in the Unicode specification. + * @since 1.1 + */ + public static final byte LOWERCASE_LETTER = 2; + + /** + * General category "Lt" in the Unicode specification. + * @since 1.1 + */ + public static final byte TITLECASE_LETTER = 3; + + /** + * General category "Lm" in the Unicode specification. + * @since 1.1 + */ + public static final byte MODIFIER_LETTER = 4; + + /** + * General category "Lo" in the Unicode specification. + * @since 1.1 + */ + public static final byte OTHER_LETTER = 5; + + /** + * General category "Mn" in the Unicode specification. + * @since 1.1 + */ + public static final byte NON_SPACING_MARK = 6; + + /** + * General category "Me" in the Unicode specification. + * @since 1.1 + */ + public static final byte ENCLOSING_MARK = 7; + + /** + * General category "Mc" in the Unicode specification. + * @since 1.1 + */ + public static final byte COMBINING_SPACING_MARK = 8; + + /** + * General category "Nd" in the Unicode specification. + * @since 1.1 + */ + public static final byte DECIMAL_DIGIT_NUMBER = 9; + + /** + * General category "Nl" in the Unicode specification. + * @since 1.1 + */ + public static final byte LETTER_NUMBER = 10; + + /** + * General category "No" in the Unicode specification. + * @since 1.1 + */ + public static final byte OTHER_NUMBER = 11; + + /** + * General category "Zs" in the Unicode specification. + * @since 1.1 + */ + public static final byte SPACE_SEPARATOR = 12; + + /** + * General category "Zl" in the Unicode specification. + * @since 1.1 + */ + public static final byte LINE_SEPARATOR = 13; + + /** + * General category "Zp" in the Unicode specification. + * @since 1.1 + */ + public static final byte PARAGRAPH_SEPARATOR = 14; + + /** + * General category "Cc" in the Unicode specification. + * @since 1.1 + */ + public static final byte CONTROL = 15; + + /** + * General category "Cf" in the Unicode specification. + * @since 1.1 + */ + public static final byte FORMAT = 16; + + /** + * General category "Co" in the Unicode specification. + * @since 1.1 + */ + public static final byte PRIVATE_USE = 18; + + /** + * General category "Cs" in the Unicode specification. + * @since 1.1 + */ + public static final byte SURROGATE = 19; + + /** + * General category "Pd" in the Unicode specification. + * @since 1.1 + */ + public static final byte DASH_PUNCTUATION = 20; + + /** + * General category "Ps" in the Unicode specification. + * @since 1.1 + */ + public static final byte START_PUNCTUATION = 21; + + /** + * General category "Pe" in the Unicode specification. + * @since 1.1 + */ + public static final byte END_PUNCTUATION = 22; + + /** + * General category "Pc" in the Unicode specification. + * @since 1.1 + */ + public static final byte CONNECTOR_PUNCTUATION = 23; + + /** + * General category "Po" in the Unicode specification. + * @since 1.1 + */ + public static final byte OTHER_PUNCTUATION = 24; + + /** + * General category "Sm" in the Unicode specification. + * @since 1.1 + */ + public static final byte MATH_SYMBOL = 25; + + /** + * General category "Sc" in the Unicode specification. + * @since 1.1 + */ + public static final byte CURRENCY_SYMBOL = 26; + + /** + * General category "Sk" in the Unicode specification. + * @since 1.1 + */ + public static final byte MODIFIER_SYMBOL = 27; + + /** + * General category "So" in the Unicode specification. + * @since 1.1 + */ + public static final byte OTHER_SYMBOL = 28; + + /** + * General category "Pi" in the Unicode specification. + * @since 1.4 + */ + public static final byte INITIAL_QUOTE_PUNCTUATION = 29; + + /** + * General category "Pf" in the Unicode specification. + * @since 1.4 + */ + public static final byte FINAL_QUOTE_PUNCTUATION = 30; /** * Error flag. Use int (code point) to avoid confusion with U+FFFF. */ - static final int ERROR = 0xFFFFFFFF; + static final int ERROR = 0xFFFFFFFF; /** @@ -402,7 +375,7 @@ * values have undefined directionality in the Unicode specification. * @since 1.4 */ - public static final byte DIRECTIONALITY_UNDEFINED = -1; + public static final byte DIRECTIONALITY_UNDEFINED = -1; /** * Strong bidirectional character type "L" in the Unicode specification. @@ -609,9 +582,9 @@ /** * Instances of this class represent particular subsets of the Unicode * character set. The only family of subsets defined in the - * Character class is {@link Character.UnicodeBlock - * UnicodeBlock}. Other portions of the Java API may define other - * subsets for their own purposes. + * Character class is {@link Character.UnicodeBlock}. + * Other portions of the Java API may define other subsets for their + * own purposes. * * @since 1.2 */ @@ -624,6 +597,7 @@ * * @exception NullPointerException if name is null * @param name The name of this subset + * @exception NullPointerException if name is null */ protected Subset(String name) { if (name == null) { @@ -662,6 +636,9 @@ } } + // See http://www.unicode.org/Public/UNIDATA/Blocks.txt + // for the latest specification of Unicode Blocks. + /** * A family of character subsets representing the character blocks in the * Unicode specification. Character blocks generally define characters @@ -672,37 +649,35 @@ */ public static final class UnicodeBlock extends Subset { - private static Map map = new HashMap(); - - /** - * Create a UnicodeBlock with the given identifier name. + private static Map map + = new HashMap(256); + + /** + * Creates a UnicodeBlock with the given identifier name. * This name must be the same as the block identifier. */ private UnicodeBlock(String idName) { super(idName); - map.put(idName.toUpperCase(Locale.US), this); + map.put(idName, this); } /** - * Create a UnicodeBlock with the given identifier name and + * Creates a UnicodeBlock with the given identifier name and * alias name. */ private UnicodeBlock(String idName, String alias) { this(idName); - map.put(alias.toUpperCase(Locale.US), this); + map.put(alias, this); } /** - * Create a UnicodeBlock with the given identifier name and + * Creates a UnicodeBlock with the given identifier name and * alias names. */ - private UnicodeBlock(String idName, String[] aliasName) { + private UnicodeBlock(String idName, String... aliases) { this(idName); - if (aliasName != null) { - for(int x=0; xnull if the character is not a * member of a defined block. * - *

Note: This method cannot handle supplementary - * characters. To support all Unicode characters, - * including supplementary characters, use the {@link - * #of(int)} method. + *

Note: This method cannot handle + * supplementary + * characters. To support all Unicode characters, including + * supplementary characters, use the {@link #of(int)} method. * * @param c The character in question * @return The UnicodeBlock instance representing the @@ -2462,22 +2556,21 @@ return of((int)c); } - /** * Returns the object representing the Unicode block * containing the given character (Unicode code point), or * null if the character is not a member of a * defined block. * - * @param codePoint the character (Unicode code point) in question. + * @param codePoint the character (Unicode code point) in question. * @return The UnicodeBlock instance representing the * Unicode block of which this character is a member, or * null if the character is not a member of any * Unicode block - * @exception IllegalArgumentException if the specified - * codePoint is an invalid Unicode code point. - * @see Character#isValidCodePoint(int) - * @since 1.5 + * @exception IllegalArgumentException if the specified + * codePoint is an invalid Unicode code point. + * @see Character#isValidCodePoint(int) + * @since 1.5 */ public static UnicodeBlock of(int codePoint) { if (!isValidCodePoint(codePoint)) { @@ -2519,7 +2612,7 @@ *

  • The text representation of each constant UnicodeBlock identifier. * For example, this method will return the {@link #BASIC_LATIN} block if * provided with the "BASIC_LATIN" name. This form replaces all spaces and - * hyphens in the canonical name with underscores. + * hyphens in the canonical name with underscores. * * Finally, character case is ignored for all of the valid block name forms. * For example, "BASIC_LATIN" and "basic_latin" are both valid block names. @@ -2538,7 +2631,7 @@ * @since 1.5 */ public static final UnicodeBlock forName(String blockName) { - UnicodeBlock block = (UnicodeBlock)map.get(blockName.toUpperCase(Locale.US)); + UnicodeBlock block = map.get(blockName.toUpperCase(Locale.US)); if (block == null) { throw new IllegalArgumentException(); } @@ -3627,7 +3720,7 @@ private static HashMap aliases; static { - aliases = new HashMap(); + aliases = new HashMap(128); aliases.put("ARAB", ARABIC); aliases.put("ARMI", IMPERIAL_ARAMAIC); aliases.put("ARMN", ARMENIAN); @@ -3809,7 +3902,7 @@ static final Character cache[] = new Character[127 + 1]; static { - for(int i = 0; i < cache.length; i++) + for (int i = 0; i < cache.length; i++) cache[i] = new Character((char)i); } } @@ -3832,7 +3925,7 @@ * @since 1.5 */ public static Character valueOf(char c) { - if(c <= 127) { // must cache + if (c <= 127) { // must cache return CharacterCache.cache[(int)c]; } return new Character(c); @@ -3914,7 +4007,29 @@ * @since 1.5 */ public static boolean isValidCodePoint(int codePoint) { - return codePoint >= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT; + // Optimized form of: + // codePoint >= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT + int plane = codePoint >>> 16; + return plane < ((MAX_CODE_POINT + 1) >>> 16); + } + + /** + * Determines whether the specified character (Unicode code point) + * is in the Basic Multilingual Plane (BMP). + * Such code points can be represented using a single {@code char}. + * + * @param codePoint the character (Unicode code point) to be tested + * @return {@code true} if the specified code point is between + * {@link #MIN_VALUE} and {@link #MAX_VALUE} inclusive; + * {@code false} otherwise. + * @since 1.7 + */ + public static boolean isBmpCodePoint(int codePoint) { + return codePoint >>> 16 == 0; + // Optimized form of: + // codePoint >= MIN_VALUE && codePoint <= MAX_VALUE + // We consistently use logical shift (>>>) to facilitate + // additional runtime optimizations. } /** @@ -3930,7 +4045,7 @@ */ public static boolean isSupplementaryCodePoint(int codePoint) { return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT - && codePoint <= MAX_CODE_POINT; + && codePoint < MAX_CODE_POINT + 1; } /** @@ -3949,12 +4064,13 @@ * {@link #MIN_HIGH_SURROGATE} and * {@link #MAX_HIGH_SURROGATE} inclusive; * {@code false} otherwise. - * @see #isLowSurrogate(char) + * @see Character#isLowSurrogate(char) * @see Character.UnicodeBlock#of(int) * @since 1.5 */ public static boolean isHighSurrogate(char ch) { - return ch >= MIN_HIGH_SURROGATE && ch <= MAX_HIGH_SURROGATE; + // Help VM constant-fold; MAX_HIGH_SURROGATE + 1 == MIN_LOW_SURROGATE + return ch >= MIN_HIGH_SURROGATE && ch < (MAX_HIGH_SURROGATE + 1); } /** @@ -3973,11 +4089,11 @@ * {@link #MIN_LOW_SURROGATE} and * {@link #MAX_LOW_SURROGATE} inclusive; * {@code false} otherwise. - * @see #isHighSurrogate(char) + * @see Character#isHighSurrogate(char) * @since 1.5 */ public static boolean isLowSurrogate(char ch) { - return ch >= MIN_LOW_SURROGATE && ch <= MAX_LOW_SURROGATE; + return ch >= MIN_LOW_SURROGATE && ch < (MAX_LOW_SURROGATE + 1); } /** @@ -4001,7 +4117,7 @@ * @since 1.7 */ public static boolean isSurrogate(char ch) { - return ch >= MIN_SURROGATE && ch <= MAX_SURROGATE; + return ch >= MIN_SURROGATE && ch < (MAX_SURROGATE + 1); } /** @@ -4039,11 +4155,11 @@ * * @param codePoint the character (Unicode code point) to be tested. * @return 2 if the character is a valid supplementary character; 1 otherwise. - * @see #isSupplementaryCodePoint(int) + * @see Character#isSupplementaryCodePoint(int) * @since 1.5 */ public static int charCount(int codePoint) { - return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT? 2 : 1; + return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT ? 2 : 1; } /** @@ -4160,6 +4276,7 @@ return codePointAtImpl(a, index, limit); } + // throws ArrayIndexOutofBoundsException if index out of bounds static int codePointAtImpl(char[] a, int index, int limit) { char c1 = a[index++]; if (isHighSurrogate(c1)) { @@ -4266,6 +4383,7 @@ return codePointBeforeImpl(a, index, start); } + // throws ArrayIndexOutofBoundsException if index-1 out of bounds static int codePointBeforeImpl(char[] a, int index, int start) { char c2 = a[--index]; if (isLowSurrogate(c2)) { @@ -4280,6 +4398,63 @@ } /** + * Returns the leading surrogate (a + * + * high surrogate code unit) of the + * + * surrogate pair + * representing the specified supplementary character (Unicode + * code point) in the UTF-16 encoding. If the specified character + * is not a + * supplementary character, + * an unspecified {@code char} is returned. + * + *

    If + * {@link #isSupplementaryCodePoint isSupplementaryCodePoint(x)} + * is {@code true}, then + * {@link #isHighSurrogate isHighSurrogate}{@code (highSurrogate(x))} and + * {@link #toCodePoint toCodePoint}{@code (highSurrogate(x), }{@link #lowSurrogate lowSurrogate}{@code (x)) == x} + * are also always {@code true}. + * + * @param codePoint a supplementary character (Unicode code point) + * @return the leading surrogate code unit used to represent the + * character in the UTF-16 encoding + * @since 1.7 + */ + public static char highSurrogate(int codePoint) { + return (char) ((codePoint >>> 10) + + (MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10))); + } + + /** + * Returns the trailing surrogate (a + * + * low surrogate code unit) of the + * + * surrogate pair + * representing the specified supplementary character (Unicode + * code point) in the UTF-16 encoding. If the specified character + * is not a + * supplementary character, + * an unspecified {@code char} is returned. + * + *

    If + * {@link #isSupplementaryCodePoint isSupplementaryCodePoint(x)} + * is {@code true}, then + * {@link #isLowSurrogate isLowSurrogate}{@code (lowSurrogate(x))} and + * {@link #toCodePoint toCodePoint}{@code (}{@link #highSurrogate highSurrogate}{@code (x), lowSurrogate(x)) == x} + * are also always {@code true}. + * + * @param codePoint a supplementary character (Unicode code point) + * @return the trailing surrogate code unit used to represent the + * character in the UTF-16 encoding + * @since 1.7 + */ + public static char lowSurrogate(int codePoint) { + return (char) ((codePoint & 0x3ff) + MIN_LOW_SURROGATE); + } + + /** * Converts the specified character (Unicode code point) to its * UTF-16 representation. If the specified code point is a BMP * (Basic Multilingual Plane or Plane 0) value, the same value is @@ -4311,15 +4486,15 @@ * @since 1.5 */ public static int toChars(int codePoint, char[] dst, int dstIndex) { - if (codePoint < 0 || codePoint > MAX_CODE_POINT) { + if (isBmpCodePoint(codePoint)) { + dst[dstIndex] = (char) codePoint; + return 1; + } else if (isValidCodePoint(codePoint)) { + toSurrogates(codePoint, dst, dstIndex); + return 2; + } else { throw new IllegalArgumentException(); } - if (codePoint < MIN_SUPPLEMENTARY_CODE_POINT) { - dst[dstIndex] = (char) codePoint; - return 1; - } - toSurrogates(codePoint, dst, dstIndex); - return 2; } /** @@ -4339,22 +4514,21 @@ * @since 1.5 */ public static char[] toChars(int codePoint) { - if (codePoint < 0 || codePoint > MAX_CODE_POINT) { + if (isBmpCodePoint(codePoint)) { + return new char[] { (char) codePoint }; + } else if (isValidCodePoint(codePoint)) { + char[] result = new char[2]; + toSurrogates(codePoint, result, 0); + return result; + } else { throw new IllegalArgumentException(); } - if (codePoint < MIN_SUPPLEMENTARY_CODE_POINT) { - return new char[] { (char) codePoint }; - } - char[] result = new char[2]; - toSurrogates(codePoint, result, 0); - return result; } static void toSurrogates(int codePoint, char[] dst, int index) { // We write elements "backwards" to guarantee all-or-nothing - dst[index+1] = (char)((codePoint & 0x3ff) + MIN_LOW_SURROGATE); - dst[index] = (char)((codePoint >>> 10) - + (MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10))); + dst[index+1] = lowSurrogate(codePoint); + dst[index] = highSurrogate(codePoint); } /** @@ -4385,13 +4559,12 @@ if (beginIndex < 0 || endIndex > length || beginIndex > endIndex) { throw new IndexOutOfBoundsException(); } - int n = 0; + int n = endIndex - beginIndex; for (int i = beginIndex; i < endIndex; ) { - n++; - if (isHighSurrogate(seq.charAt(i++))) { - if (i < endIndex && isLowSurrogate(seq.charAt(i))) { - i++; - } + if (isHighSurrogate(seq.charAt(i++)) && i < endIndex && + isLowSurrogate(seq.charAt(i))) { + n--; + i++; } } return n; @@ -4425,13 +4598,12 @@ static int codePointCountImpl(char[] a, int offset, int count) { int endIndex = offset + count; - int n = 0; + int n = count; for (int i = offset; i < endIndex; ) { - n++; - if (isHighSurrogate(a[i++])) { - if (i < endIndex && isLowSurrogate(a[i])) { - i++; - } + if (isHighSurrogate(a[i++]) && i < endIndex && + isLowSurrogate(a[i])) { + n--; + i++; } } return n; @@ -4470,10 +4642,9 @@ if (codePointOffset >= 0) { int i; for (i = 0; x < length && i < codePointOffset; i++) { - if (isHighSurrogate(seq.charAt(x++))) { - if (x < length && isLowSurrogate(seq.charAt(x))) { - x++; - } + if (isHighSurrogate(seq.charAt(x++)) && x < length && + isLowSurrogate(seq.charAt(x))) { + x++; } } if (i < codePointOffset) { @@ -4482,10 +4653,9 @@ } else { int i; for (i = codePointOffset; x > 0 && i < 0; i++) { - if (isLowSurrogate(seq.charAt(--x))) { - if (x > 0 && isHighSurrogate(seq.charAt(x-1))) { - x--; - } + if (isLowSurrogate(seq.charAt(--x)) && x > 0 && + isHighSurrogate(seq.charAt(x-1))) { + x--; } } if (i < 0) { @@ -4544,10 +4714,9 @@ int limit = start + count; int i; for (i = 0; x < limit && i < codePointOffset; i++) { - if (isHighSurrogate(a[x++])) { - if (x < limit && isLowSurrogate(a[x])) { - x++; - } + if (isHighSurrogate(a[x++]) && x < limit && + isLowSurrogate(a[x])) { + x++; } } if (i < codePointOffset) { @@ -4556,10 +4725,9 @@ } else { int i; for (i = codePointOffset; x > start && i < 0; i++) { - if (isLowSurrogate(a[--x])) { - if (x > start && isHighSurrogate(a[x-1])) { - x--; - } + if (isLowSurrogate(a[--x]) && x > start && + isHighSurrogate(a[x-1])) { + x--; } } if (i < 0) { @@ -4569,7 +4737,7 @@ return x; } - /** + /** * Determines if the specified character is a lowercase character. *

    * A character is lowercase if its general category type, provided @@ -4594,10 +4762,10 @@ * @param ch the character to be tested. * @return true if the character is lowercase; * false otherwise. - * @see java.lang.Character#isLowerCase(char) - * @see java.lang.Character#isTitleCase(char) - * @see java.lang.Character#toLowerCase(char) - * @see java.lang.Character#getType(char) + * @see Character#isLowerCase(char) + * @see Character#isTitleCase(char) + * @see Character#toLowerCase(char) + * @see Character#getType(char) */ public static boolean isLowerCase(char ch) { return isLowerCase((int)ch); @@ -4624,17 +4792,17 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character is lowercase; * false otherwise. - * @see java.lang.Character#isLowerCase(int) - * @see java.lang.Character#isTitleCase(int) - * @see java.lang.Character#toLowerCase(int) - * @see java.lang.Character#getType(int) + * @see Character#isLowerCase(int) + * @see Character#isTitleCase(int) + * @see Character#toLowerCase(int) + * @see Character#getType(int) * @since 1.5 */ public static boolean isLowerCase(int codePoint) { return getType(codePoint) == Character.LOWERCASE_LETTER; } - /** + /** * Determines if the specified character is an uppercase character. *

    * A character is uppercase if its general category type, provided by @@ -4658,10 +4826,10 @@ * @param ch the character to be tested. * @return true if the character is uppercase; * false otherwise. - * @see java.lang.Character#isLowerCase(char) - * @see java.lang.Character#isTitleCase(char) - * @see java.lang.Character#toUpperCase(char) - * @see java.lang.Character#getType(char) + * @see Character#isLowerCase(char) + * @see Character#isTitleCase(char) + * @see Character#toUpperCase(char) + * @see Character#getType(char) * @since 1.0 */ public static boolean isUpperCase(char ch) { @@ -4687,10 +4855,10 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character is uppercase; * false otherwise. - * @see java.lang.Character#isLowerCase(int) - * @see java.lang.Character#isTitleCase(int) - * @see java.lang.Character#toUpperCase(int) - * @see java.lang.Character#getType(int) + * @see Character#isLowerCase(int) + * @see Character#isTitleCase(int) + * @see Character#toUpperCase(int) + * @see Character#getType(int) * @since 1.5 */ public static boolean isUpperCase(int codePoint) { @@ -4728,10 +4896,10 @@ * @param ch the character to be tested. * @return true if the character is titlecase; * false otherwise. - * @see java.lang.Character#isLowerCase(char) - * @see java.lang.Character#isUpperCase(char) - * @see java.lang.Character#toTitleCase(char) - * @see java.lang.Character#getType(char) + * @see Character#isLowerCase(char) + * @see Character#isUpperCase(char) + * @see Character#toTitleCase(char) + * @see Character#getType(char) * @since 1.0.2 */ public static boolean isTitleCase(char ch) { @@ -4764,10 +4932,10 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character is titlecase; * false otherwise. - * @see java.lang.Character#isLowerCase(int) - * @see java.lang.Character#isUpperCase(int) - * @see java.lang.Character#toTitleCase(int) - * @see java.lang.Character#getType(int) + * @see Character#isLowerCase(int) + * @see Character#isUpperCase(int) + * @see Character#toTitleCase(int) + * @see Character#getType(int) * @since 1.5 */ public static boolean isTitleCase(int codePoint) { @@ -4805,9 +4973,9 @@ * @param ch the character to be tested. * @return true if the character is a digit; * false otherwise. - * @see java.lang.Character#digit(char, int) - * @see java.lang.Character#forDigit(int, int) - * @see java.lang.Character#getType(char) + * @see Character#digit(char, int) + * @see Character#forDigit(int, int) + * @see Character#getType(char) */ public static boolean isDigit(char ch) { return isDigit((int)ch); @@ -4839,8 +5007,8 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character is a digit; * false otherwise. - * @see java.lang.Character#forDigit(int, int) - * @see java.lang.Character#getType(int) + * @see Character#forDigit(int, int) + * @see Character#getType(int) * @since 1.5 */ public static boolean isDigit(int codePoint) { @@ -4864,12 +5032,12 @@ * @param ch the character to be tested * @return true if the character has a defined meaning * in Unicode; false otherwise. - * @see java.lang.Character#isDigit(char) - * @see java.lang.Character#isLetter(char) - * @see java.lang.Character#isLetterOrDigit(char) - * @see java.lang.Character#isLowerCase(char) - * @see java.lang.Character#isTitleCase(char) - * @see java.lang.Character#isUpperCase(char) + * @see Character#isDigit(char) + * @see Character#isLetter(char) + * @see Character#isLetterOrDigit(char) + * @see Character#isLowerCase(char) + * @see Character#isTitleCase(char) + * @see Character#isUpperCase(char) * @since 1.0.2 */ public static boolean isDefined(char ch) { @@ -4888,12 +5056,12 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character has a defined meaning * in Unicode; false otherwise. - * @see java.lang.Character#isDigit(int) - * @see java.lang.Character#isLetter(int) - * @see java.lang.Character#isLetterOrDigit(int) - * @see java.lang.Character#isLowerCase(int) - * @see java.lang.Character#isTitleCase(int) - * @see java.lang.Character#isUpperCase(int) + * @see Character#isDigit(int) + * @see Character#isLetter(int) + * @see Character#isLetterOrDigit(int) + * @see Character#isLowerCase(int) + * @see Character#isTitleCase(int) + * @see Character#isUpperCase(int) * @since 1.5 */ public static boolean isDefined(int codePoint) { @@ -4925,15 +5093,15 @@ * @param ch the character to be tested. * @return true if the character is a letter; * false otherwise. - * @see java.lang.Character#isDigit(char) - * @see java.lang.Character#isJavaIdentifierStart(char) - * @see java.lang.Character#isJavaLetter(char) - * @see java.lang.Character#isJavaLetterOrDigit(char) - * @see java.lang.Character#isLetterOrDigit(char) - * @see java.lang.Character#isLowerCase(char) - * @see java.lang.Character#isTitleCase(char) - * @see java.lang.Character#isUnicodeIdentifierStart(char) - * @see java.lang.Character#isUpperCase(char) + * @see Character#isDigit(char) + * @see Character#isJavaIdentifierStart(char) + * @see Character#isJavaLetter(char) + * @see Character#isJavaLetterOrDigit(char) + * @see Character#isLetterOrDigit(char) + * @see Character#isLowerCase(char) + * @see Character#isTitleCase(char) + * @see Character#isUnicodeIdentifierStart(char) + * @see Character#isUpperCase(char) */ public static boolean isLetter(char ch) { return isLetter((int)ch); @@ -4959,13 +5127,13 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character is a letter; * false otherwise. - * @see java.lang.Character#isDigit(int) - * @see java.lang.Character#isJavaIdentifierStart(int) - * @see java.lang.Character#isLetterOrDigit(int) - * @see java.lang.Character#isLowerCase(int) - * @see java.lang.Character#isTitleCase(int) - * @see java.lang.Character#isUnicodeIdentifierStart(int) - * @see java.lang.Character#isUpperCase(int) + * @see Character#isDigit(int) + * @see Character#isJavaIdentifierStart(int) + * @see Character#isLetterOrDigit(int) + * @see Character#isLowerCase(int) + * @see Character#isTitleCase(int) + * @see Character#isUnicodeIdentifierStart(int) + * @see Character#isUpperCase(int) * @since 1.5 */ public static boolean isLetter(int codePoint) { @@ -4993,12 +5161,12 @@ * @param ch the character to be tested. * @return true if the character is a letter or digit; * false otherwise. - * @see java.lang.Character#isDigit(char) - * @see java.lang.Character#isJavaIdentifierPart(char) - * @see java.lang.Character#isJavaLetter(char) - * @see java.lang.Character#isJavaLetterOrDigit(char) - * @see java.lang.Character#isLetter(char) - * @see java.lang.Character#isUnicodeIdentifierPart(char) + * @see Character#isDigit(char) + * @see Character#isJavaIdentifierPart(char) + * @see Character#isJavaLetter(char) + * @see Character#isJavaLetterOrDigit(char) + * @see Character#isLetter(char) + * @see Character#isUnicodeIdentifierPart(char) * @since 1.0.2 */ public static boolean isLetterOrDigit(char ch) { @@ -5016,10 +5184,10 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character is a letter or digit; * false otherwise. - * @see java.lang.Character#isDigit(int) - * @see java.lang.Character#isJavaIdentifierPart(int) - * @see java.lang.Character#isLetter(int) - * @see java.lang.Character#isUnicodeIdentifierPart(int) + * @see Character#isDigit(int) + * @see Character#isJavaIdentifierPart(int) + * @see Character#isLetter(int) + * @see Character#isUnicodeIdentifierPart(int) * @since 1.5 */ public static boolean isLetterOrDigit(int codePoint) { @@ -5048,12 +5216,12 @@ * @param ch the character to be tested. * @return true if the character may start a Java * identifier; false otherwise. - * @see java.lang.Character#isJavaLetterOrDigit(char) - * @see java.lang.Character#isJavaIdentifierStart(char) - * @see java.lang.Character#isJavaIdentifierPart(char) - * @see java.lang.Character#isLetter(char) - * @see java.lang.Character#isLetterOrDigit(char) - * @see java.lang.Character#isUnicodeIdentifierStart(char) + * @see Character#isJavaLetterOrDigit(char) + * @see Character#isJavaIdentifierStart(char) + * @see Character#isJavaIdentifierPart(char) + * @see Character#isLetter(char) + * @see Character#isLetterOrDigit(char) + * @see Character#isUnicodeIdentifierStart(char) * @since 1.02 * @deprecated Replaced by isJavaIdentifierStart(char). */ @@ -5083,13 +5251,13 @@ * @param ch the character to be tested. * @return true if the character may be part of a * Java identifier; false otherwise. - * @see java.lang.Character#isJavaLetter(char) - * @see java.lang.Character#isJavaIdentifierStart(char) - * @see java.lang.Character#isJavaIdentifierPart(char) - * @see java.lang.Character#isLetter(char) - * @see java.lang.Character#isLetterOrDigit(char) - * @see java.lang.Character#isUnicodeIdentifierPart(char) - * @see java.lang.Character#isIdentifierIgnorable(char) + * @see Character#isJavaLetter(char) + * @see Character#isJavaIdentifierStart(char) + * @see Character#isJavaIdentifierPart(char) + * @see Character#isLetter(char) + * @see Character#isLetterOrDigit(char) + * @see Character#isUnicodeIdentifierPart(char) + * @see Character#isIdentifierIgnorable(char) * @since 1.02 * @deprecated Replaced by isJavaIdentifierPart(char). */ @@ -5119,9 +5287,9 @@ * @param ch the character to be tested. * @return true if the character may start a Java identifier; * false otherwise. - * @see java.lang.Character#isJavaIdentifierPart(char) - * @see java.lang.Character#isLetter(char) - * @see java.lang.Character#isUnicodeIdentifierStart(char) + * @see Character#isJavaIdentifierPart(char) + * @see Character#isLetter(char) + * @see Character#isUnicodeIdentifierStart(char) * @see javax.lang.model.SourceVersion#isIdentifier(CharSequence) * @since 1.1 */ @@ -5148,9 +5316,9 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character may start a Java identifier; * false otherwise. - * @see java.lang.Character#isJavaIdentifierPart(int) - * @see java.lang.Character#isLetter(int) - * @see java.lang.Character#isUnicodeIdentifierStart(int) + * @see Character#isJavaIdentifierPart(int) + * @see Character#isLetter(int) + * @see Character#isUnicodeIdentifierStart(int) * @see javax.lang.model.SourceVersion#isIdentifier(CharSequence) * @since 1.5 */ @@ -5184,10 +5352,10 @@ * @param ch the character to be tested. * @return true if the character may be part of a * Java identifier; false otherwise. - * @see java.lang.Character#isIdentifierIgnorable(char) - * @see java.lang.Character#isJavaIdentifierStart(char) - * @see java.lang.Character#isLetterOrDigit(char) - * @see java.lang.Character#isUnicodeIdentifierPart(char) + * @see Character#isIdentifierIgnorable(char) + * @see Character#isJavaIdentifierStart(char) + * @see Character#isLetterOrDigit(char) + * @see Character#isUnicodeIdentifierPart(char) * @see javax.lang.model.SourceVersion#isIdentifier(CharSequence) * @since 1.1 */ @@ -5217,10 +5385,10 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character may be part of a * Java identifier; false otherwise. - * @see java.lang.Character#isIdentifierIgnorable(int) - * @see java.lang.Character#isJavaIdentifierStart(int) - * @see java.lang.Character#isLetterOrDigit(int) - * @see java.lang.Character#isUnicodeIdentifierPart(int) + * @see Character#isIdentifierIgnorable(int) + * @see Character#isJavaIdentifierStart(int) + * @see Character#isLetterOrDigit(int) + * @see Character#isUnicodeIdentifierPart(int) * @see javax.lang.model.SourceVersion#isIdentifier(CharSequence) * @since 1.5 */ @@ -5248,9 +5416,9 @@ * @param ch the character to be tested. * @return true if the character may start a Unicode * identifier; false otherwise. - * @see java.lang.Character#isJavaIdentifierStart(char) - * @see java.lang.Character#isLetter(char) - * @see java.lang.Character#isUnicodeIdentifierPart(char) + * @see Character#isJavaIdentifierStart(char) + * @see Character#isLetter(char) + * @see Character#isUnicodeIdentifierPart(char) * @since 1.1 */ public static boolean isUnicodeIdentifierStart(char ch) { @@ -5272,9 +5440,9 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character may start a Unicode * identifier; false otherwise. - * @see java.lang.Character#isJavaIdentifierStart(int) - * @see java.lang.Character#isLetter(int) - * @see java.lang.Character#isUnicodeIdentifierPart(int) + * @see Character#isJavaIdentifierStart(int) + * @see Character#isLetter(int) + * @see Character#isUnicodeIdentifierPart(int) * @since 1.5 */ public static boolean isUnicodeIdentifierStart(int codePoint) { @@ -5306,10 +5474,10 @@ * @param ch the character to be tested. * @return true if the character may be part of a * Unicode identifier; false otherwise. - * @see java.lang.Character#isIdentifierIgnorable(char) - * @see java.lang.Character#isJavaIdentifierPart(char) - * @see java.lang.Character#isLetterOrDigit(char) - * @see java.lang.Character#isUnicodeIdentifierStart(char) + * @see Character#isIdentifierIgnorable(char) + * @see Character#isJavaIdentifierPart(char) + * @see Character#isLetterOrDigit(char) + * @see Character#isUnicodeIdentifierStart(char) * @since 1.1 */ public static boolean isUnicodeIdentifierPart(char ch) { @@ -5335,10 +5503,10 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character may be part of a * Unicode identifier; false otherwise. - * @see java.lang.Character#isIdentifierIgnorable(int) - * @see java.lang.Character#isJavaIdentifierPart(int) - * @see java.lang.Character#isLetterOrDigit(int) - * @see java.lang.Character#isUnicodeIdentifierStart(int) + * @see Character#isIdentifierIgnorable(int) + * @see Character#isJavaIdentifierPart(int) + * @see Character#isLetterOrDigit(int) + * @see Character#isUnicodeIdentifierStart(int) * @since 1.5 */ public static boolean isUnicodeIdentifierPart(int codePoint) { @@ -5372,8 +5540,8 @@ * @return true if the character is an ignorable control * character that may be part of a Java or Unicode identifier; * false otherwise. - * @see java.lang.Character#isJavaIdentifierPart(char) - * @see java.lang.Character#isUnicodeIdentifierPart(char) + * @see Character#isJavaIdentifierPart(char) + * @see Character#isUnicodeIdentifierPart(char) * @since 1.1 */ public static boolean isIdentifierIgnorable(char ch) { @@ -5402,8 +5570,8 @@ * @return true if the character is an ignorable control * character that may be part of a Java or Unicode identifier; * false otherwise. - * @see java.lang.Character#isJavaIdentifierPart(int) - * @see java.lang.Character#isUnicodeIdentifierPart(int) + * @see Character#isJavaIdentifierPart(int) + * @see Character#isUnicodeIdentifierPart(int) * @since 1.5 */ public static boolean isIdentifierIgnorable(int codePoint) { @@ -5419,7 +5587,7 @@ * does not always return true for some ranges of * characters, particularly those that are symbols or ideographs. * - *

    In general, {@link java.lang.String#toLowerCase()} should be used to map + *

    In general, {@link String#toLowerCase()} should be used to map * characters to lowercase. String case mapping methods * have several benefits over Character case mapping methods. * String case mapping methods can perform locale-sensitive @@ -5434,8 +5602,8 @@ * @param ch the character to be converted. * @return the lowercase equivalent of the character, if any; * otherwise, the character itself. - * @see java.lang.Character#isLowerCase(char) - * @see java.lang.String#toLowerCase() + * @see Character#isLowerCase(char) + * @see String#toLowerCase() */ public static char toLowerCase(char ch) { return (char)toLowerCase((int)ch); @@ -5451,7 +5619,7 @@ * does not always return true for some ranges of * characters, particularly those that are symbols or ideographs. * - *

    In general, {@link java.lang.String#toLowerCase()} should be used to map + *

    In general, {@link String#toLowerCase()} should be used to map * characters to lowercase. String case mapping methods * have several benefits over Character case mapping methods. * String case mapping methods can perform locale-sensitive @@ -5461,8 +5629,8 @@ * @param codePoint the character (Unicode code point) to be converted. * @return the lowercase equivalent of the character (Unicode code * point), if any; otherwise, the character itself. - * @see java.lang.Character#isLowerCase(int) - * @see java.lang.String#toLowerCase() + * @see Character#isLowerCase(int) + * @see String#toLowerCase() * * @since 1.5 */ @@ -5479,7 +5647,7 @@ * does not always return true for some ranges of * characters, particularly those that are symbols or ideographs. * - *

    In general, {@link java.lang.String#toUpperCase()} should be used to map + *

    In general, {@link String#toUpperCase()} should be used to map * characters to uppercase. String case mapping methods * have several benefits over Character case mapping methods. * String case mapping methods can perform locale-sensitive @@ -5494,8 +5662,8 @@ * @param ch the character to be converted. * @return the uppercase equivalent of the character, if any; * otherwise, the character itself. - * @see java.lang.Character#isUpperCase(char) - * @see java.lang.String#toUpperCase() + * @see Character#isUpperCase(char) + * @see String#toUpperCase() */ public static char toUpperCase(char ch) { return (char)toUpperCase((int)ch); @@ -5511,7 +5679,7 @@ * does not always return true for some ranges of * characters, particularly those that are symbols or ideographs. * - *

    In general, {@link java.lang.String#toUpperCase()} should be used to map + *

    In general, {@link String#toUpperCase()} should be used to map * characters to uppercase. String case mapping methods * have several benefits over Character case mapping methods. * String case mapping methods can perform locale-sensitive @@ -5521,8 +5689,8 @@ * @param codePoint the character (Unicode code point) to be converted. * @return the uppercase equivalent of the character, if any; * otherwise, the character itself. - * @see java.lang.Character#isUpperCase(int) - * @see java.lang.String#toUpperCase() + * @see Character#isUpperCase(int) + * @see String#toUpperCase() * * @since 1.5 */ @@ -5553,9 +5721,9 @@ * @param ch the character to be converted. * @return the titlecase equivalent of the character, if any; * otherwise, the character itself. - * @see java.lang.Character#isTitleCase(char) - * @see java.lang.Character#toLowerCase(char) - * @see java.lang.Character#toUpperCase(char) + * @see Character#isTitleCase(char) + * @see Character#toLowerCase(char) + * @see Character#toUpperCase(char) * @since 1.0.2 */ public static char toTitleCase(char ch) { @@ -5580,9 +5748,9 @@ * @param codePoint the character (Unicode code point) to be converted. * @return the titlecase equivalent of the character, if any; * otherwise, the character itself. - * @see java.lang.Character#isTitleCase(int) - * @see java.lang.Character#toLowerCase(int) - * @see java.lang.Character#toUpperCase(int) + * @see Character#isTitleCase(int) + * @see Character#toLowerCase(int) + * @see Character#toUpperCase(int) * @since 1.5 */ public static int toTitleCase(int codePoint) { @@ -5624,8 +5792,8 @@ * @param radix the radix. * @return the numeric value represented by the character in the * specified radix. - * @see java.lang.Character#forDigit(int, int) - * @see java.lang.Character#isDigit(char) + * @see Character#forDigit(int, int) + * @see Character#isDigit(char) */ public static int digit(char ch, int radix) { return digit((int)ch, radix); @@ -5661,8 +5829,8 @@ * @param radix the radix. * @return the numeric value represented by the character in the * specified radix. - * @see java.lang.Character#forDigit(int, int) - * @see java.lang.Character#isDigit(int) + * @see Character#forDigit(int, int) + * @see Character#isDigit(int) * @since 1.5 */ public static int digit(int codePoint, int radix) { @@ -5699,8 +5867,8 @@ * @return the numeric value of the character, as a nonnegative int * value; -2 if the character has a numeric value that is not a * nonnegative integer; -1 if the character has no numeric value. - * @see java.lang.Character#forDigit(int, int) - * @see java.lang.Character#isDigit(char) + * @see Character#forDigit(int, int) + * @see Character#isDigit(char) * @since 1.1 */ public static int getNumericValue(char ch) { @@ -5732,8 +5900,8 @@ * @return the numeric value of the character, as a nonnegative int * value; -2 if the character has a numeric value that is not a * nonnegative integer; -1 if the character has no numeric value. - * @see java.lang.Character#forDigit(int, int) - * @see java.lang.Character#isDigit(int) + * @see Character#forDigit(int, int) + * @see Character#isDigit(int) * @since 1.5 */ public static int getNumericValue(int codePoint) { @@ -5760,8 +5928,8 @@ * @param ch the character to be tested. * @return true if the character is ISO-LATIN-1 white * space; false otherwise. - * @see java.lang.Character#isSpaceChar(char) - * @see java.lang.Character#isWhitespace(char) + * @see Character#isSpaceChar(char) + * @see Character#isWhitespace(char) * @deprecated Replaced by isWhitespace(char). */ @Deprecated @@ -5795,7 +5963,7 @@ * @param ch the character to be tested. * @return true if the character is a space character; * false otherwise. - * @see java.lang.Character#isWhitespace(char) + * @see Character#isWhitespace(char) * @since 1.1 */ public static boolean isSpaceChar(char ch) { @@ -5818,7 +5986,7 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character is a space character; * false otherwise. - * @see java.lang.Character#isWhitespace(int) + * @see Character#isWhitespace(int) * @since 1.5 */ public static boolean isSpaceChar(int codePoint) { @@ -5856,7 +6024,7 @@ * @param ch the character to be tested. * @return true if the character is a Java whitespace * character; false otherwise. - * @see java.lang.Character#isSpaceChar(char) + * @see Character#isSpaceChar(char) * @since 1.1 */ public static boolean isWhitespace(char ch) { @@ -5888,7 +6056,7 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character is a Java whitespace * character; false otherwise. - * @see java.lang.Character#isSpaceChar(int) + * @see Character#isSpaceChar(int) * @since 1.5 */ public static boolean isWhitespace(int codePoint) { @@ -5911,8 +6079,8 @@ * @return true if the character is an ISO control character; * false otherwise. * - * @see java.lang.Character#isSpaceChar(char) - * @see java.lang.Character#isWhitespace(char) + * @see Character#isSpaceChar(char) + * @see Character#isWhitespace(char) * @since 1.1 */ public static boolean isISOControl(char ch) { @@ -5929,13 +6097,16 @@ * @param codePoint the character (Unicode code point) to be tested. * @return true if the character is an ISO control character; * false otherwise. - * @see java.lang.Character#isSpaceChar(int) - * @see java.lang.Character#isWhitespace(int) + * @see Character#isSpaceChar(int) + * @see Character#isWhitespace(int) * @since 1.5 */ public static boolean isISOControl(int codePoint) { - return (codePoint >= 0x0000 && codePoint <= 0x001F) || - (codePoint >= 0x007F && codePoint <= 0x009F); + // Optimized form of: + // (codePoint >= 0x00 && codePoint <= 0x1F) || + // (codePoint >= 0x7F && codePoint <= 0x9F); + return codePoint <= 0x9F && + (codePoint >= 0x7F || (codePoint >>> 5 == 0)); } /** @@ -5949,36 +6120,36 @@ * @param ch the character to be tested. * @return a value of type int representing the * character's general category. - * @see java.lang.Character#COMBINING_SPACING_MARK - * @see java.lang.Character#CONNECTOR_PUNCTUATION - * @see java.lang.Character#CONTROL - * @see java.lang.Character#CURRENCY_SYMBOL - * @see java.lang.Character#DASH_PUNCTUATION - * @see java.lang.Character#DECIMAL_DIGIT_NUMBER - * @see java.lang.Character#ENCLOSING_MARK - * @see java.lang.Character#END_PUNCTUATION - * @see java.lang.Character#FINAL_QUOTE_PUNCTUATION - * @see java.lang.Character#FORMAT - * @see java.lang.Character#INITIAL_QUOTE_PUNCTUATION - * @see java.lang.Character#LETTER_NUMBER - * @see java.lang.Character#LINE_SEPARATOR - * @see java.lang.Character#LOWERCASE_LETTER - * @see java.lang.Character#MATH_SYMBOL - * @see java.lang.Character#MODIFIER_LETTER - * @see java.lang.Character#MODIFIER_SYMBOL - * @see java.lang.Character#NON_SPACING_MARK - * @see java.lang.Character#OTHER_LETTER - * @see java.lang.Character#OTHER_NUMBER - * @see java.lang.Character#OTHER_PUNCTUATION - * @see java.lang.Character#OTHER_SYMBOL - * @see java.lang.Character#PARAGRAPH_SEPARATOR - * @see java.lang.Character#PRIVATE_USE - * @see java.lang.Character#SPACE_SEPARATOR - * @see java.lang.Character#START_PUNCTUATION - * @see java.lang.Character#SURROGATE - * @see java.lang.Character#TITLECASE_LETTER - * @see java.lang.Character#UNASSIGNED - * @see java.lang.Character#UPPERCASE_LETTER + * @see Character#COMBINING_SPACING_MARK + * @see Character#CONNECTOR_PUNCTUATION + * @see Character#CONTROL + * @see Character#CURRENCY_SYMBOL + * @see Character#DASH_PUNCTUATION + * @see Character#DECIMAL_DIGIT_NUMBER + * @see Character#ENCLOSING_MARK + * @see Character#END_PUNCTUATION + * @see Character#FINAL_QUOTE_PUNCTUATION + * @see Character#FORMAT + * @see Character#INITIAL_QUOTE_PUNCTUATION + * @see Character#LETTER_NUMBER + * @see Character#LINE_SEPARATOR + * @see Character#LOWERCASE_LETTER + * @see Character#MATH_SYMBOL + * @see Character#MODIFIER_LETTER + * @see Character#MODIFIER_SYMBOL + * @see Character#NON_SPACING_MARK + * @see Character#OTHER_LETTER + * @see Character#OTHER_NUMBER + * @see Character#OTHER_PUNCTUATION + * @see Character#OTHER_SYMBOL + * @see Character#PARAGRAPH_SEPARATOR + * @see Character#PRIVATE_USE + * @see Character#SPACE_SEPARATOR + * @see Character#START_PUNCTUATION + * @see Character#SURROGATE + * @see Character#TITLECASE_LETTER + * @see Character#UNASSIGNED + * @see Character#UPPERCASE_LETTER * @since 1.1 */ public static int getType(char ch) { @@ -6047,9 +6218,9 @@ * @param radix the radix. * @return the char representation of the specified digit * in the specified radix. - * @see java.lang.Character#MIN_RADIX - * @see java.lang.Character#MAX_RADIX - * @see java.lang.Character#digit(char, int) + * @see Character#MIN_RADIX + * @see Character#MAX_RADIX + * @see Character#digit(char, int) */ public static char forDigit(int digit, int radix) { if ((digit >= radix) || (digit < 0)) { @@ -6230,10 +6401,10 @@ * @return either the uppercase equivalent of the character, if * any, or an error flag (Character.ERROR) * that indicates that a 1:M char mapping exists. - * @see java.lang.Character#isLowerCase(char) - * @see java.lang.Character#isUpperCase(char) - * @see java.lang.Character#toLowerCase(char) - * @see java.lang.Character#toTitleCase(char) + * @see Character#isLowerCase(char) + * @see Character#isUpperCase(char) + * @see Character#toLowerCase(char) + * @see Character#toTitleCase(char) * @since 1.4 */ static int toUpperCaseEx(int codePoint) { @@ -6254,8 +6425,7 @@ */ static char[] toUpperCaseCharArray(int codePoint) { // As of Unicode 4.0, 1:M uppercasings only happen in the BMP. - assert isValidCodePoint(codePoint) && - !isSupplementaryCodePoint(codePoint); + assert isBmpCodePoint(codePoint); return CharacterData.of(codePoint).toUpperCaseCharArray(codePoint); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/lang/String.java --- a/jdk/src/share/classes/java/lang/String.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/lang/String.java Wed Jul 05 17:18:12 2017 +0200 @@ -38,7 +38,6 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; - /** * The String class represents character strings. All * string literals in Java programs, such as "abc", are @@ -99,6 +98,8 @@ * * @author Lee Boynton * @author Arthur van Hoff + * @author Martin Buchholz + * @author Ulf Zibis * @see java.lang.Object#toString() * @see java.lang.StringBuffer * @see java.lang.StringBuilder @@ -273,32 +274,32 @@ throw new StringIndexOutOfBoundsException(offset + count); } + final int end = offset + count; + // Pass 1: Compute precise size of char[] - int n = 0; - for (int i = offset; i < offset + count; i++) { + int n = count; + for (int i = offset; i < end; i++) { int c = codePoints[i]; - if (c >= Character.MIN_CODE_POINT && - c < Character.MIN_SUPPLEMENTARY_CODE_POINT) - n += 1; - else if (Character.isSupplementaryCodePoint(c)) - n += 2; + if (Character.isBmpCodePoint(c)) + continue; + else if (Character.isValidCodePoint(c)) + n++; else throw new IllegalArgumentException(Integer.toString(c)); } // Pass 2: Allocate and fill in char[] - char[] v = new char[n]; - for (int i = offset, j = 0; i < offset + count; i++) { + final char[] v = new char[n]; + + for (int i = offset, j = 0; i < end; i++, j++) { int c = codePoints[i]; - if (c < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - v[j++] = (char) c; - } else { - Character.toSurrogates(c, v, j); - j += 2; - } + if (Character.isBmpCodePoint(c)) + v[j] = (char) c; + else + Character.toSurrogates(c, v, j++); } this.value = v; - this.count = v.length; + this.count = n; this.offset = 0; } @@ -1573,9 +1574,6 @@ * if the character does not occur. */ public int indexOf(int ch, int fromIndex) { - int max = offset + count; - char v[] = value; - if (fromIndex < 0) { fromIndex = 0; } else if (fromIndex >= count) { @@ -1583,29 +1581,36 @@ return -1; } - int i = offset + fromIndex; if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // handle most cases here (ch is a BMP code point or a // negative value (invalid code point)) - for (; i < max ; i++) { - if (v[i] == ch) { + final char[] value = this.value; + final int offset = this.offset; + final int max = offset + count; + for (int i = offset + fromIndex; i < max ; i++) { + if (value[i] == ch) { return i - offset; } } return -1; + } else { + return indexOfSupplementary(ch, fromIndex); } + } - if (ch <= Character.MAX_CODE_POINT) { - // handle supplementary characters here - char[] surrogates = Character.toChars(ch); - for (; i < max; i++) { - if (v[i] == surrogates[0]) { - if (i + 1 == max) { - break; - } - if (v[i+1] == surrogates[1]) { - return i - offset; - } + /** + * Handles (rare) calls of indexOf with a supplementary character. + */ + private int indexOfSupplementary(int ch, int fromIndex) { + if (Character.isValidCodePoint(ch)) { + final char[] value = this.value; + final int offset = this.offset; + final char hi = Character.highSurrogate(ch); + final char lo = Character.lowSurrogate(ch); + final int max = offset + count - 1; + for (int i = offset + fromIndex; i < max; i++) { + if (value[i] == hi && value[i+1] == lo) { + return i - offset; } } } @@ -1674,34 +1679,36 @@ * if the character does not occur before that point. */ public int lastIndexOf(int ch, int fromIndex) { - int min = offset; - char v[] = value; - - int i = offset + ((fromIndex >= count) ? count - 1 : fromIndex); - if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // handle most cases here (ch is a BMP code point or a // negative value (invalid code point)) - for (; i >= min ; i--) { - if (v[i] == ch) { + final char[] value = this.value; + final int offset = this.offset; + int i = offset + Math.min(fromIndex, count - 1); + for (; i >= offset ; i--) { + if (value[i] == ch) { return i - offset; } } return -1; + } else { + return lastIndexOfSupplementary(ch, fromIndex); } + } - int max = offset + count; - if (ch <= Character.MAX_CODE_POINT) { - // handle supplementary characters here - char[] surrogates = Character.toChars(ch); - for (; i >= min; i--) { - if (v[i] == surrogates[0]) { - if (i + 1 == max) { - break; - } - if (v[i+1] == surrogates[1]) { - return i - offset; - } + /** + * Handles (rare) calls of lastIndexOf with a supplementary character. + */ + private int lastIndexOfSupplementary(int ch, int fromIndex) { + if (Character.isValidCodePoint(ch)) { + final char[] value = this.value; + final int offset = this.offset; + char hi = Character.highSurrogate(ch); + char lo = Character.lowSurrogate(ch); + int i = offset + Math.min(fromIndex, count - 2); + for (; i >= offset; i--) { + if (value[i] == hi && value[i+1] == lo) { + return i - offset; } } } @@ -1710,18 +1717,17 @@ /** * Returns the index within this string of the first occurrence of the - * specified substring. The integer returned is the smallest value - * k such that: + * specified substring. + * + *

    The returned index is the smallest value k for which: *

          * this.startsWith(str, k)
          * 
    - * is true. + * If no such value of k exists, then {@code -1} is returned. * - * @param str any string. - * @return if the string argument occurs as a substring within this - * object, then the index of the first character of the first - * such substring is returned; if it does not occur as a - * substring, -1 is returned. + * @param str the substring to search for. + * @return the index of the first occurrence of the specified substring, + * or {@code -1} if there is no such occurrence. */ public int indexOf(String str) { return indexOf(str, 0); @@ -1729,17 +1735,19 @@ /** * Returns the index within this string of the first occurrence of the - * specified substring, starting at the specified index. The integer - * returned is the smallest value k for which: + * specified substring, starting at the specified index. + * + *

    The returned index is the smallest value k for which: *

    -     *     k >= Math.min(fromIndex, this.length()) && this.startsWith(str, k)
    +     * k >= fromIndex && this.startsWith(str, k)
          * 
    - * If no such value of k exists, then -1 is returned. + * If no such value of k exists, then {@code -1} is returned. * - * @param str the substring for which to search. + * @param str the substring to search for. * @param fromIndex the index from which to start the search. - * @return the index within this string of the first occurrence of the - * specified substring, starting at the specified index. + * @return the index of the first occurrence of the specified substring, + * starting at the specified index, + * or {@code -1} if there is no such occurrence. */ public int indexOf(String str, int fromIndex) { return indexOf(value, offset, count, @@ -1798,20 +1806,19 @@ } /** - * Returns the index within this string of the rightmost occurrence - * of the specified substring. The rightmost empty string "" is - * considered to occur at the index value this.length(). - * The returned index is the largest value k such that + * Returns the index within this string of the last occurrence of the + * specified substring. The last occurrence of the empty string "" + * is considered to occur at the index value {@code this.length()}. + * + *

    The returned index is the largest value k for which: *

    -     * this.startsWith(str, k)
    +     * this.startsWith(str, k)
          * 
    - * is true. + * If no such value of k exists, then {@code -1} is returned. * * @param str the substring to search for. - * @return if the string argument occurs one or more times as a substring - * within this object, then the index of the first character of - * the last such substring is returned. If it does not occur as - * a substring, -1 is returned. + * @return the index of the last occurrence of the specified substring, + * or {@code -1} if there is no such occurrence. */ public int lastIndexOf(String str) { return lastIndexOf(str, count); @@ -1820,16 +1827,18 @@ /** * Returns the index within this string of the last occurrence of the * specified substring, searching backward starting at the specified index. - * The integer returned is the largest value k such that: + * + *

    The returned index is the largest value k for which: *

    -     *     k <= Math.min(fromIndex, this.length()) && this.startsWith(str, k)
    +     * k <= fromIndex && this.startsWith(str, k)
          * 
    - * If no such value of k exists, then -1 is returned. + * If no such value of k exists, then {@code -1} is returned. * * @param str the substring to search for. * @param fromIndex the index to start the search from. - * @return the index within this string of the last occurrence of the - * specified substring. + * @return the index of the last occurrence of the specified substring, + * searching backward from the specified index, + * or {@code -1} if there is no such occurrence. */ public int lastIndexOf(String str, int fromIndex) { return lastIndexOf(value, offset, count, diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/lang/System.java --- a/jdk/src/share/classes/java/lang/System.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/lang/System.java Wed Jul 05 17:18:12 2017 +0200 @@ -69,7 +69,7 @@ * corresponds to keyboard input or another input source specified by * the host environment or user. */ - public final static InputStream in = nullInputStream(); + public final static InputStream in = null; /** * The "standard" output stream. This stream is already @@ -96,7 +96,7 @@ * @see java.io.PrintStream#println(java.lang.Object) * @see java.io.PrintStream#println(java.lang.String) */ - public final static PrintStream out = nullPrintStream(); + public final static PrintStream out = null; /** * The "standard" error output stream. This stream is already @@ -110,7 +110,7 @@ * variable out, has been redirected to a file or other * destination that is typically not continuously monitored. */ - public final static PrintStream err = nullPrintStream(); + public final static PrintStream err = null; /* The security manager for the system. */ @@ -1093,26 +1093,6 @@ public static native String mapLibraryName(String libname); /** - * The following two methods exist because in, out, and err must be - * initialized to null. The compiler, however, cannot be permitted to - * inline access to them, since they are later set to more sensible values - * by initializeSystemClass(). - */ - private static InputStream nullInputStream() throws NullPointerException { - if (currentTimeMillis() > 0) { - return null; - } - throw new NullPointerException(); - } - - private static PrintStream nullPrintStream() throws NullPointerException { - if (currentTimeMillis() > 0) { - return null; - } - throw new NullPointerException(); - } - - /** * Initialize the system class. Called after thread initialization. */ private static void initializeSystemClass() { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/lang/Throwable.java --- a/jdk/src/share/classes/java/lang/Throwable.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/lang/Throwable.java Wed Jul 05 17:18:12 2017 +0200 @@ -25,6 +25,7 @@ package java.lang; import java.io.*; +import java.util.*; /** * The Throwable class is the superclass of all errors and @@ -102,7 +103,7 @@ * lowLevelOp(); * } catch (LowLevelException le) { * throw (HighLevelException) - new HighLevelException().initCause(le); // Legacy constructor + * new HighLevelException().initCause(le); // Legacy constructor * } * * @@ -193,6 +194,24 @@ */ /** + * The list of suppressed exceptions, as returned by + * {@link #getSuppressedExceptions()}. + * + * @serial + * @since 1.7 + */ + private List suppressedExceptions = Collections.emptyList(); + + /** Message for trying to suppress a null exception. */ + private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception."; + + /** Caption for labeling causative exception stack traces */ + private static final String CAUSE_CAPTION = "Caused by: "; + + /** Caption for labeling suppressed exception stack traces */ + private static final String SUPPRESSED_CAPTION = "Suppressed: "; + + /** * Constructs a new throwable with null as its detail message. * The cause is not initialized, and may subsequently be initialized by a * call to {@link #initCause}. @@ -469,6 +488,52 @@ * class LowLevelException extends Exception { * } * + * As of release 7, the platform supports the notion of + * suppressed exceptions (in conjunction with automatic + * resource management blocks). Any exceptions that were + * suppressed in order to deliver an exception are printed out + * beneath the stack trace. The format of this information + * depends on the implementation, but the following example may be + * regarded as typical: + * + *
    +     * Exception in thread "main" java.lang.Exception: Something happened
    +     *  at Foo.bar(Foo.java:10)
    +     *  at Foo.main(Foo.java:5)
    +     *  Suppressed: Resource$CloseFailException: Resource ID = 0
    +     *          at Resource.close(Resource.java:26)
    +     *          at Foo.bar(Foo.java:9)
    +     *          ... 1 more
    +     * 
    + * Note that the "... n more" notation is used on suppressed exceptions + * just at it is used on causes. Unlike causes, suppressed exceptions are + * indented beyond their "containing exceptions." + * + *

    An exception can have both a cause and one or more suppressed + * exceptions: + *

    +     * Exception in thread "main" java.lang.Exception: Main block
    +     *  at Foo3.main(Foo3.java:7)
    +     *  Suppressed: Resource$CloseFailException: Resource ID = 2
    +     *          at Resource.close(Resource.java:26)
    +     *          at Foo3.main(Foo3.java:5)
    +     *  Suppressed: Resource$CloseFailException: Resource ID = 1
    +     *          at Resource.close(Resource.java:26)
    +     *          at Foo3.main(Foo3.java:5)
    +     * Caused by: java.lang.Exception: I did it
    +     *  at Foo3.main(Foo3.java:8)
    +     * 
    + * Likewise, a suppressed exception can have a cause: + *
    +     * Exception in thread "main" java.lang.Exception: Main block
    +     *  at Foo4.main(Foo4.java:6)
    +     *  Suppressed: Resource2$CloseFailException: Resource ID = 1
    +     *          at Resource2.close(Resource2.java:20)
    +     *          at Foo4.main(Foo4.java:5)
    +     *  Caused by: java.lang.Exception: Rats, you caught me
    +     *          at Resource2$CloseFailException.(Resource2.java:45)
    +     *          ... 2 more
    +     * 
    */ public void printStackTrace() { printStackTrace(System.err); @@ -480,44 +545,71 @@ * @param s PrintStream to use for output */ public void printStackTrace(PrintStream s) { - synchronized (s) { + printStackTrace(new WrappedPrintStream(s)); + } + + private void printStackTrace(PrintStreamOrWriter s) { + Set dejaVu = new HashSet(); + dejaVu.add(this); + + synchronized (s.lock()) { + // Print our stack trace s.println(this); StackTraceElement[] trace = getOurStackTrace(); - for (int i=0; i < trace.length; i++) - s.println("\tat " + trace[i]); + for (StackTraceElement traceElement : trace) + s.println("\tat " + traceElement); + // Print suppressed exceptions, if any + for (Throwable se : suppressedExceptions) + se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu); + + // Print cause, if any Throwable ourCause = getCause(); if (ourCause != null) - ourCause.printStackTraceAsCause(s, trace); + ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu); } } /** - * Print our stack trace as a cause for the specified stack trace. + * Print our stack trace as an enclosed exception for the specified + * stack trace. */ - private void printStackTraceAsCause(PrintStream s, - StackTraceElement[] causedTrace) - { - // assert Thread.holdsLock(s); + private void printEnclosedStackTrace(PrintStreamOrWriter s, + StackTraceElement[] enclosingTrace, + String caption, + String prefix, + Set dejaVu) { + assert Thread.holdsLock(s.lock()); + if (dejaVu.contains(this)) { + s.println("\t[CIRCULAR REFERENCE:" + this + "]"); + } else { + dejaVu.add(this); + // Compute number of frames in common between this and enclosing trace + StackTraceElement[] trace = getOurStackTrace(); + int m = trace.length - 1; + int n = enclosingTrace.length - 1; + while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) { + m--; n--; + } + int framesInCommon = trace.length - 1 - m; - // Compute number of frames in common between this and caused - StackTraceElement[] trace = getOurStackTrace(); - int m = trace.length-1, n = causedTrace.length-1; - while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) { - m--; n--; + // Print our stack trace + s.println(prefix + caption + this); + for (int i = 0; i <= m; i++) + s.println(prefix + "\tat " + trace[i]); + if (framesInCommon != 0) + s.println(prefix + "\t... " + framesInCommon + " more"); + + // Print suppressed exceptions, if any + for (Throwable se : suppressedExceptions) + se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, + prefix +"\t", dejaVu); + + // Print cause, if any + Throwable ourCause = getCause(); + if (ourCause != null) + ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu); } - int framesInCommon = trace.length - 1 - m; - - s.println("Caused by: " + this); - for (int i=0; i <= m; i++) - s.println("\tat " + trace[i]); - if (framesInCommon != 0) - s.println("\t... " + framesInCommon + " more"); - - // Recurse if we have a cause - Throwable ourCause = getCause(); - if (ourCause != null) - ourCause.printStackTraceAsCause(s, trace); } /** @@ -528,44 +620,51 @@ * @since JDK1.1 */ public void printStackTrace(PrintWriter s) { - synchronized (s) { - s.println(this); - StackTraceElement[] trace = getOurStackTrace(); - for (int i=0; i < trace.length; i++) - s.println("\tat " + trace[i]); - - Throwable ourCause = getCause(); - if (ourCause != null) - ourCause.printStackTraceAsCause(s, trace); - } + printStackTrace(new WrappedPrintWriter(s)); } /** - * Print our stack trace as a cause for the specified stack trace. + * Wrapper class for PrintStream and PrintWriter to enable a single + * implementation of printStackTrace. */ - private void printStackTraceAsCause(PrintWriter s, - StackTraceElement[] causedTrace) - { - // assert Thread.holdsLock(s); + private abstract static class PrintStreamOrWriter { + /** Returns the object to be locked when using this StreamOrWriter */ + abstract Object lock(); + + /** Prints the specified string as a line on this StreamOrWriter */ + abstract void println(Object o); + } - // Compute number of frames in common between this and caused - StackTraceElement[] trace = getOurStackTrace(); - int m = trace.length-1, n = causedTrace.length-1; - while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) { - m--; n--; + private static class WrappedPrintStream extends PrintStreamOrWriter { + private final PrintStream printStream; + + WrappedPrintStream(PrintStream printStream) { + this.printStream = printStream; + } + + Object lock() { + return printStream; } - int framesInCommon = trace.length - 1 - m; + + void println(Object o) { + printStream.println(o); + } + } + + private static class WrappedPrintWriter extends PrintStreamOrWriter { + private final PrintWriter printWriter; - s.println("Caused by: " + this); - for (int i=0; i <= m; i++) - s.println("\tat " + trace[i]); - if (framesInCommon != 0) - s.println("\t... " + framesInCommon + " more"); + WrappedPrintWriter(PrintWriter printWriter) { + this.printWriter = printWriter; + } - // Recurse if we have a cause - Throwable ourCause = getCause(); - if (ourCause != null) - ourCause.printStackTraceAsCause(s, trace); + Object lock() { + return printWriter; + } + + void println(Object o) { + printWriter.println(o); + } } /** @@ -667,10 +766,60 @@ */ native StackTraceElement getStackTraceElement(int index); - private synchronized void writeObject(java.io.ObjectOutputStream s) + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); // read in all fields + List suppressed = Collections.emptyList(); + if (suppressedExceptions != null && + !suppressedExceptions.isEmpty()) { // Copy Throwables to new list + suppressed = new ArrayList(); + for(Throwable t : suppressedExceptions) { + if (t == null) + throw new NullPointerException(NULL_CAUSE_MESSAGE); + suppressed.add(t); + } + } + suppressedExceptions = suppressed; + } + + private synchronized void writeObject(ObjectOutputStream s) throws IOException { getOurStackTrace(); // Ensure that stackTrace field is initialized. s.defaultWriteObject(); } + + /** + * Adds the specified exception to the list of exceptions that + * were suppressed, typically by the automatic resource management + * statement, in order to deliver this exception. + * + * @param exception the exception to be added to the list of + * suppressed exceptions + * @throws NullPointerException if {@code exception} is null + * @since 1.7 + */ + public synchronized void addSuppressedException(Throwable exception) { + if (exception == null) + throw new NullPointerException(NULL_CAUSE_MESSAGE); + + if (suppressedExceptions.size() == 0) + suppressedExceptions = new ArrayList(); + suppressedExceptions.add(exception); + } + + private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0]; + + /** + * Returns an array containing all of the exceptions that were + * suppressed, typically by the automatic resource management + * statement, in order to deliver this exception. + * + * @return an array containing all of the exceptions that were + * suppressed to deliver this exception. + * @since 1.7 + */ + public Throwable[] getSuppressedExceptions() { + return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); + } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/net/Inet6Address.java --- a/jdk/src/share/classes/java/net/Inet6Address.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/net/Inet6Address.java Wed Jul 05 17:18:12 2017 +0200 @@ -427,8 +427,9 @@ try { scope_id = deriveNumericScope (scope_ifname); } catch (UnknownHostException e) { - // should not happen - assert false; + // typically should not happen, but it may be that + // the machine being used for deserialization has + // the same interface name but without IPv6 configured. } } } catch (SocketException e) {} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/nio/Bits.java --- a/jdk/src/share/classes/java/nio/Bits.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/nio/Bits.java Wed Jul 05 17:18:12 2017 +0200 @@ -41,25 +41,19 @@ // -- Swapping -- static short swap(short x) { - return (short)((x << 8) | - ((char)x >>> 8)); + return Short.reverseBytes(x); } static char swap(char x) { - return (char)((x << 8) | - (x >>> 8)); + return Character.reverseBytes(x); } static int swap(int x) { - return ((x << 24) | - ((x & 0x0000ff00) << 8) | - ((x & 0x00ff0000) >>> 8) | - (x >>> 24)); + return Integer.reverseBytes(x); } static long swap(long x) { - return (((long)swap((int)x) << 32) | - ((long)swap((int)(x >>> 32)) & 0xffffffffL)); + return Long.reverseBytes(x); } @@ -71,52 +65,52 @@ static char getCharL(ByteBuffer bb, int bi) { return makeChar(bb._get(bi + 1), - bb._get(bi + 0)); + bb._get(bi )); } static char getCharL(long a) { return makeChar(_get(a + 1), - _get(a + 0)); + _get(a )); } static char getCharB(ByteBuffer bb, int bi) { - return makeChar(bb._get(bi + 0), + return makeChar(bb._get(bi ), bb._get(bi + 1)); } static char getCharB(long a) { - return makeChar(_get(a + 0), + return makeChar(_get(a ), _get(a + 1)); } static char getChar(ByteBuffer bb, int bi, boolean bigEndian) { - return (bigEndian ? getCharB(bb, bi) : getCharL(bb, bi)); + return bigEndian ? getCharB(bb, bi) : getCharL(bb, bi); } static char getChar(long a, boolean bigEndian) { - return (bigEndian ? getCharB(a) : getCharL(a)); + return bigEndian ? getCharB(a) : getCharL(a); } private static byte char1(char x) { return (byte)(x >> 8); } - private static byte char0(char x) { return (byte)(x >> 0); } + private static byte char0(char x) { return (byte)(x ); } static void putCharL(ByteBuffer bb, int bi, char x) { - bb._put(bi + 0, char0(x)); + bb._put(bi , char0(x)); bb._put(bi + 1, char1(x)); } static void putCharL(long a, char x) { - _put(a + 0, char0(x)); + _put(a , char0(x)); _put(a + 1, char1(x)); } static void putCharB(ByteBuffer bb, int bi, char x) { - bb._put(bi + 0, char1(x)); + bb._put(bi , char1(x)); bb._put(bi + 1, char0(x)); } static void putCharB(long a, char x) { - _put(a + 0, char1(x)); + _put(a , char1(x)); _put(a + 1, char0(x)); } @@ -143,52 +137,52 @@ static short getShortL(ByteBuffer bb, int bi) { return makeShort(bb._get(bi + 1), - bb._get(bi + 0)); + bb._get(bi )); } static short getShortL(long a) { return makeShort(_get(a + 1), - _get(a)); + _get(a )); } static short getShortB(ByteBuffer bb, int bi) { - return makeShort(bb._get(bi + 0), + return makeShort(bb._get(bi ), bb._get(bi + 1)); } static short getShortB(long a) { - return makeShort(_get(a), + return makeShort(_get(a ), _get(a + 1)); } static short getShort(ByteBuffer bb, int bi, boolean bigEndian) { - return (bigEndian ? getShortB(bb, bi) : getShortL(bb, bi)); + return bigEndian ? getShortB(bb, bi) : getShortL(bb, bi); } static short getShort(long a, boolean bigEndian) { - return (bigEndian ? getShortB(a) : getShortL(a)); + return bigEndian ? getShortB(a) : getShortL(a); } private static byte short1(short x) { return (byte)(x >> 8); } - private static byte short0(short x) { return (byte)(x >> 0); } + private static byte short0(short x) { return (byte)(x ); } static void putShortL(ByteBuffer bb, int bi, short x) { - bb._put(bi + 0, short0(x)); + bb._put(bi , short0(x)); bb._put(bi + 1, short1(x)); } static void putShortL(long a, short x) { - _put(a, short0(x)); + _put(a , short0(x)); _put(a + 1, short1(x)); } static void putShortB(ByteBuffer bb, int bi, short x) { - bb._put(bi + 0, short1(x)); + bb._put(bi , short1(x)); bb._put(bi + 1, short0(x)); } static void putShortB(long a, short x) { - _put(a, short1(x)); + _put(a , short1(x)); _put(a + 1, short0(x)); } @@ -210,76 +204,76 @@ // -- get/put int -- static private int makeInt(byte b3, byte b2, byte b1, byte b0) { - return (((b3 & 0xff) << 24) | + return (((b3 ) << 24) | ((b2 & 0xff) << 16) | ((b1 & 0xff) << 8) | - ((b0 & 0xff) << 0)); + ((b0 & 0xff) )); } static int getIntL(ByteBuffer bb, int bi) { return makeInt(bb._get(bi + 3), bb._get(bi + 2), bb._get(bi + 1), - bb._get(bi + 0)); + bb._get(bi )); } static int getIntL(long a) { return makeInt(_get(a + 3), _get(a + 2), _get(a + 1), - _get(a + 0)); + _get(a )); } static int getIntB(ByteBuffer bb, int bi) { - return makeInt(bb._get(bi + 0), + return makeInt(bb._get(bi ), bb._get(bi + 1), bb._get(bi + 2), bb._get(bi + 3)); } static int getIntB(long a) { - return makeInt(_get(a + 0), + return makeInt(_get(a ), _get(a + 1), _get(a + 2), _get(a + 3)); } static int getInt(ByteBuffer bb, int bi, boolean bigEndian) { - return (bigEndian ? getIntB(bb, bi) : getIntL(bb, bi)); + return bigEndian ? getIntB(bb, bi) : getIntL(bb, bi) ; } static int getInt(long a, boolean bigEndian) { - return (bigEndian ? getIntB(a) : getIntL(a)); + return bigEndian ? getIntB(a) : getIntL(a) ; } private static byte int3(int x) { return (byte)(x >> 24); } private static byte int2(int x) { return (byte)(x >> 16); } private static byte int1(int x) { return (byte)(x >> 8); } - private static byte int0(int x) { return (byte)(x >> 0); } + private static byte int0(int x) { return (byte)(x ); } static void putIntL(ByteBuffer bb, int bi, int x) { bb._put(bi + 3, int3(x)); bb._put(bi + 2, int2(x)); bb._put(bi + 1, int1(x)); - bb._put(bi + 0, int0(x)); + bb._put(bi , int0(x)); } static void putIntL(long a, int x) { _put(a + 3, int3(x)); _put(a + 2, int2(x)); _put(a + 1, int1(x)); - _put(a + 0, int0(x)); + _put(a , int0(x)); } static void putIntB(ByteBuffer bb, int bi, int x) { - bb._put(bi + 0, int3(x)); + bb._put(bi , int3(x)); bb._put(bi + 1, int2(x)); bb._put(bi + 2, int1(x)); bb._put(bi + 3, int0(x)); } static void putIntB(long a, int x) { - _put(a + 0, int3(x)); + _put(a , int3(x)); _put(a + 1, int2(x)); _put(a + 2, int1(x)); _put(a + 3, int0(x)); @@ -305,14 +299,14 @@ static private long makeLong(byte b7, byte b6, byte b5, byte b4, byte b3, byte b2, byte b1, byte b0) { - return ((((long)b7 & 0xff) << 56) | + return ((((long)b7 ) << 56) | (((long)b6 & 0xff) << 48) | (((long)b5 & 0xff) << 40) | (((long)b4 & 0xff) << 32) | (((long)b3 & 0xff) << 24) | (((long)b2 & 0xff) << 16) | (((long)b1 & 0xff) << 8) | - (((long)b0 & 0xff) << 0)); + (((long)b0 & 0xff) )); } static long getLongL(ByteBuffer bb, int bi) { @@ -323,7 +317,7 @@ bb._get(bi + 3), bb._get(bi + 2), bb._get(bi + 1), - bb._get(bi + 0)); + bb._get(bi )); } static long getLongL(long a) { @@ -334,11 +328,11 @@ _get(a + 3), _get(a + 2), _get(a + 1), - _get(a + 0)); + _get(a )); } static long getLongB(ByteBuffer bb, int bi) { - return makeLong(bb._get(bi + 0), + return makeLong(bb._get(bi ), bb._get(bi + 1), bb._get(bi + 2), bb._get(bi + 3), @@ -349,7 +343,7 @@ } static long getLongB(long a) { - return makeLong(_get(a + 0), + return makeLong(_get(a ), _get(a + 1), _get(a + 2), _get(a + 3), @@ -360,11 +354,11 @@ } static long getLong(ByteBuffer bb, int bi, boolean bigEndian) { - return (bigEndian ? getLongB(bb, bi) : getLongL(bb, bi)); + return bigEndian ? getLongB(bb, bi) : getLongL(bb, bi); } static long getLong(long a, boolean bigEndian) { - return (bigEndian ? getLongB(a) : getLongL(a)); + return bigEndian ? getLongB(a) : getLongL(a); } private static byte long7(long x) { return (byte)(x >> 56); } @@ -374,7 +368,7 @@ private static byte long3(long x) { return (byte)(x >> 24); } private static byte long2(long x) { return (byte)(x >> 16); } private static byte long1(long x) { return (byte)(x >> 8); } - private static byte long0(long x) { return (byte)(x >> 0); } + private static byte long0(long x) { return (byte)(x ); } static void putLongL(ByteBuffer bb, int bi, long x) { bb._put(bi + 7, long7(x)); @@ -384,7 +378,7 @@ bb._put(bi + 3, long3(x)); bb._put(bi + 2, long2(x)); bb._put(bi + 1, long1(x)); - bb._put(bi + 0, long0(x)); + bb._put(bi , long0(x)); } static void putLongL(long a, long x) { @@ -395,11 +389,11 @@ _put(a + 3, long3(x)); _put(a + 2, long2(x)); _put(a + 1, long1(x)); - _put(a + 0, long0(x)); + _put(a , long0(x)); } static void putLongB(ByteBuffer bb, int bi, long x) { - bb._put(bi + 0, long7(x)); + bb._put(bi , long7(x)); bb._put(bi + 1, long6(x)); bb._put(bi + 2, long5(x)); bb._put(bi + 3, long4(x)); @@ -410,7 +404,7 @@ } static void putLongB(long a, long x) { - _put(a + 0, long7(x)); + _put(a , long7(x)); _put(a + 1, long6(x)); _put(a + 2, long5(x)); _put(a + 3, long4(x)); @@ -454,11 +448,11 @@ } static float getFloat(ByteBuffer bb, int bi, boolean bigEndian) { - return (bigEndian ? getFloatB(bb, bi) : getFloatL(bb, bi)); + return bigEndian ? getFloatB(bb, bi) : getFloatL(bb, bi); } static float getFloat(long a, boolean bigEndian) { - return (bigEndian ? getFloatB(a) : getFloatL(a)); + return bigEndian ? getFloatB(a) : getFloatL(a); } static void putFloatL(ByteBuffer bb, int bi, float x) { @@ -511,11 +505,11 @@ } static double getDouble(ByteBuffer bb, int bi, boolean bigEndian) { - return (bigEndian ? getDoubleB(bb, bi) : getDoubleL(bb, bi)); + return bigEndian ? getDoubleB(bb, bi) : getDoubleL(bb, bi); } static double getDouble(long a, boolean bigEndian) { - return (bigEndian ? getDoubleB(a) : getDoubleL(a)); + return bigEndian ? getDoubleB(a) : getDoubleL(a); } static void putDoubleL(ByteBuffer bb, int bi, double x) { @@ -794,7 +788,7 @@ static native void copyFromIntArray(Object src, long srcPos, long dstAddr, long length); static native void copyToIntArray(long srcAddr, Object dst, long dstPos, - long length); + long length); static native void copyFromLongArray(Object src, long srcPos, long dstAddr, long length); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/nio/channels/FileLock.java --- a/jdk/src/share/classes/java/nio/channels/FileLock.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/FileLock.java Wed Jul 05 17:18:12 2017 +0200 @@ -116,7 +116,7 @@ * @since 1.4 */ -public abstract class FileLock { +public abstract class FileLock implements AutoCloseable { private final Channel channel; private final long position; @@ -299,6 +299,17 @@ public abstract void release() throws IOException; /** + * This method invokes the {@link #release} method. It was added + * to the class so that it could be used in conjunction with the + * automatic resource management block construct. + * + * @since 1.7 + */ + public final void close() throws IOException { + release(); + } + + /** * Returns a string describing the range, type, and validity of this lock. * * @return A descriptive string diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/util/DualPivotQuicksort.java --- a/jdk/src/share/classes/java/util/DualPivotQuicksort.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/util/DualPivotQuicksort.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ /** * This class implements the Dual-Pivot Quicksort algorithm by - * Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. The algorithm + * Vladimir Yaroslavskiy, Jon Bentley, and Josh Bloch. The algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically * faster than traditional (one-pivot) Quicksort implementations. @@ -36,7 +36,8 @@ * @author Jon Bentley * @author Josh Bloch * - * @version 2009.11.29 m765.827.12i + * @version 2010.06.21 m765.827.12i:5\7 + * @since 1.7 */ final class DualPivotQuicksort { @@ -68,7 +69,7 @@ private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 32768; /* - * Sorting methods for 7 primitive types. + * Sorting methods for seven primitive types. */ /** @@ -77,7 +78,7 @@ * @param a the array to be sorted */ public static void sort(int[] a) { - doSort(a, 0, a.length - 1); + sort(a, 0, a.length - 1, true); } /** @@ -95,98 +96,132 @@ */ public static void sort(int[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + sort(a, fromIndex, toIndex - 1, true); } /** - * Sorts the specified range of the array into ascending order. This - * method differs from the public {@code sort} method in that the - * {@code right} index is inclusive, and it does no range checking - * on {@code left} or {@code right}. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. This method differs from the public + * {@code sort} method in that the {@code right} index is inclusive, + * it does no range checking on {@code left} or {@code right}, and has + * boolean flag whether insertion sort with sentinel is used or not. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param leftmost indicates if the part is the most left in the range */ - private static void doSort(int[] a, int left, int right) { - // Use insertion sort on tiny arrays - if (right - left + 1 < INSERTION_SORT_THRESHOLD) { - for (int i = left + 1; i <= right; i++) { - int ai = a[i]; - int j; - for (j = i - 1; j >= left && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); - } - } + private static void sort(int[] a, int left, int right, boolean leftmost) { + int length = right - left + 1; - /** - * Sorts the specified range of the array into ascending order by the - * Dual-Pivot Quicksort algorithm. - * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - */ - private static void dualPivotQuicksort(int[] a, int left, int right) { - // Compute indices of five evenly spaced elements - int sixth = (right - left + 1) / 6; - int e1 = left + sixth; - int e5 = right - sixth; + // Use insertion sort on tiny arrays + if (length < INSERTION_SORT_THRESHOLD) { + if (!leftmost) { + /* + * Every element in adjoining part plays the role + * of sentinel, therefore this allows us to avoid + * the j >= left check on each iteration. + */ + for (int j, i = left + 1; i <= right; i++) { + int ai = a[i]; + for (j = i - 1; ai < a[j]; j--) { + // assert j >= left; + a[j + 1] = a[j]; + } + a[j + 1] = ai; + } + } else { + /* + * For case of leftmost part traditional (without a sentinel) + * insertion sort, optimized for server JVM, is used. + */ + for (int i = left, j = i; i < right; j = ++i) { + int ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == left) { + break; + } + } + a[j + 1] = ai; + } + } + return; + } + + // Inexpensive approximation of length / 7 + int seventh = (length >>> 3) + (length >>> 6) + 1; + + /* + * Sort five evenly spaced elements around (and including) the + * center element in the range. These elements will be used for + * pivot selection as described below. The choice for spacing + * these elements was empirically determined to work well on + * a wide variety of inputs. + */ int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + int e2 = e3 - seventh; + int e1 = e2 - seventh; + int e4 = e3 + seventh; + int e5 = e4 + seventh; - // Sort these elements using a 5-element sorting network - int ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + // Sort these elements using insertion sort + if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; } - if (ae1 > ae2) { int t = ae1; ae1 = ae2; ae2 = t; } - if (ae4 > ae5) { int t = ae4; ae4 = ae5; ae5 = t; } - if (ae1 > ae3) { int t = ae1; ae1 = ae3; ae3 = t; } - if (ae2 > ae3) { int t = ae2; ae2 = ae3; ae3 = t; } - if (ae1 > ae4) { int t = ae1; ae1 = ae4; ae4 = t; } - if (ae3 > ae4) { int t = ae3; ae3 = ae4; ae4 = t; } - if (ae2 > ae5) { int t = ae2; ae2 = ae5; ae5 = t; } - if (ae2 > ae3) { int t = ae2; ae2 = ae3; ae3 = t; } - if (ae4 > ae5) { int t = ae4; ae4 = ae5; ae5 = t; } - - a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + if (a[e3] < a[e2]) { int t = a[e3]; a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + if (a[e4] < a[e3]) { int t = a[e4]; a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t; + if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + } /* * Use the second and fourth of the five sorted elements as pivots. * These values are inexpensive approximations of the first and * second terciles of the array. Note that pivot1 <= pivot2. - * - * The pivots are stored in local variables, and the first and - * the last of the elements to be sorted are moved to the locations - * formerly occupied by the pivots. When partitioning is complete, - * the pivots are swapped back into their final positions, and - * excluded from subsequent sorting. */ - int pivot1 = ae2; a[e2] = a[left]; - int pivot2 = ae4; a[e4] = a[right]; + int pivot1 = a[e2]; + int pivot2 = a[e4]; // Pointers - int less = left + 1; // The index of first element of center part - int great = right - 1; // The index before first element of right part + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 != pivot2) { + /* + * The first and the last elements to be sorted are moved to the + * locations formerly occupied by the pivots. When partitioning + * is complete, the pivots are swapped back into their final + * positions, and excluded from subsequent sorting. + */ + a[e2] = a[left]; + a[e4] = a[right]; - if (pivotsDiffer) { + /* + * Skip elements, which are less or greater than pivot values. + */ + while (a[++less] < pivot1); + while (a[--great] > pivot2); + /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -194,16 +229,14 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ outer: for (int k = less; k <= great; k++) { int ak = a[k]; if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; } else if (ak > pivot2) { // Move a[k] to right part while (a[great] > pivot2) { @@ -213,26 +246,107 @@ } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // pivot1 <= a[great] <= pivot2 a[k] = a[great]; - a[great--] = ak; + } + a[great] = ak; + great--; + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivots + sort(a, left, less - 2, leftmost); + sort(a, great + 2, right, false); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (less < e1 && e5 < great) { + /* + * Skip elements, which are equal to pivot values. + */ + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + + /* + * Partitioning: + * + * left part center part right part + * +----------------------------------------------------------+ + * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | + * +----------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (*, less) == pivot1 + * pivot1 < all in [less, k) < pivot2 + * all in (great, *) == pivot2 + * + * Pointer k is the first index of ?-part. + */ + outer: + for (int k = less; k <= great; k++) { + int ak = a[k]; + if (ak == pivot1) { // Move a[k] to left part + a[k] = a[less]; + a[less] = ak; + less++; + } else if (ak == pivot2) { // Move a[k] to right part + while (a[great] == pivot2) { + if (great-- == k) { + break outer; + } + } + if (a[great] == pivot1) { + a[k] = a[less]; + /* + * Even though a[great] equals to pivot1, the + * assignment a[less] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point zeros + * of different signs. Therefore in float and + * double sorting methods we have to use more + * accurate assignment a[less] = a[great]. + */ + a[less] = pivot1; + less++; + } else { // pivot1 < a[great] < pivot2 + a[k] = a[great]; + } + a[great] = ak; + great--; } } } + + // Sort center part recursively + sort(a, less, great, false); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * - * left part center part right part - * +----------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +----------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +-------------------------------------------------+ + * | < pivot | == pivot | ? | > pivot | + * +-------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -240,20 +354,19 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ - for (int k = less; k <= great; k++) { - int ak = a[k]; - if (ak == pivot1) { + for (int k = left; k <= great; k++) { + if (a[k] == pivot1) { continue; } + int ak = a[k]; + if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } else { // a[k] > pivot1 - Move a[k] to right part /* * We know that pivot1 == a[e3] == pivot2. Thus, we know * that great will still be >= k when the following loop @@ -261,92 +374,33 @@ * In other words, a[e3] acts as a sentinel for great. */ while (a[great] > pivot1) { + // assert great > k; great--; } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // a[great] == pivot1 + /* + * Even though a[great] equals to pivot1, the + * assignment a[k] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point + * zeros of different signs. Therefore in float + * and double sorting methods we have to use + * more accurate assignment a[k] = a[great]. + */ a[k] = pivot1; - a[great--] = ak; } + a[great] = ak; + great--; } } - } - - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivot values - doSort(a, left, less - 2); - doSort(a, great + 2, right); - - /* - * If pivot1 == pivot2, all elements from center - * part are equal and, therefore, already sorted - */ - if (!pivotsDiffer) { - return; - } - - /* - * If center part is too large (comprises > 2/3 of the array), - * swap internal pivot values to ends - */ - if (less < e1 && great > e5) { - while (a[less] == pivot1) { - less++; - } - while (a[great] == pivot2) { - great--; - } - /* - * Partitioning: - * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 - * - * Pointer k is the first index of ?-part - */ - outer: - for (int k = less; k <= great; k++) { - int ak = a[k]; - if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] == pivot1) { - a[k] = a[less]; - a[less++] = pivot1; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great--] = pivot2; - } else if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less++] = pivot1; - } - } + // Sort left and right parts recursively + sort(a, left, less - 1, leftmost); + sort(a, great + 1, right, false); } - - // Sort center part recursively, excluding known pivot values - doSort(a, less, great); } /** @@ -355,7 +409,7 @@ * @param a the array to be sorted */ public static void sort(long[] a) { - doSort(a, 0, a.length - 1); + sort(a, 0, a.length - 1, true); } /** @@ -373,98 +427,132 @@ */ public static void sort(long[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + sort(a, fromIndex, toIndex - 1, true); } /** - * Sorts the specified range of the array into ascending order. This - * method differs from the public {@code sort} method in that the - * {@code right} index is inclusive, and it does no range checking on - * {@code left} or {@code right}. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. This method differs from the public + * {@code sort} method in that the {@code right} index is inclusive, + * it does no range checking on {@code left} or {@code right}, and has + * boolean flag whether insertion sort with sentinel is used or not. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param leftmost indicates if the part is the most left in the range */ - private static void doSort(long[] a, int left, int right) { - // Use insertion sort on tiny arrays - if (right - left + 1 < INSERTION_SORT_THRESHOLD) { - for (int i = left + 1; i <= right; i++) { - long ai = a[i]; - int j; - for (j = i - 1; j >= left && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); - } - } + private static void sort(long[] a, int left, int right, boolean leftmost) { + int length = right - left + 1; - /** - * Sorts the specified range of the array into ascending order by the - * Dual-Pivot Quicksort algorithm. - * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - */ - private static void dualPivotQuicksort(long[] a, int left, int right) { - // Compute indices of five evenly spaced elements - int sixth = (right - left + 1) / 6; - int e1 = left + sixth; - int e5 = right - sixth; + // Use insertion sort on tiny arrays + if (length < INSERTION_SORT_THRESHOLD) { + if (!leftmost) { + /* + * Every element in adjoining part plays the role + * of sentinel, therefore this allows us to avoid + * the j >= left check on each iteration. + */ + for (int j, i = left + 1; i <= right; i++) { + long ai = a[i]; + for (j = i - 1; ai < a[j]; j--) { + // assert j >= left; + a[j + 1] = a[j]; + } + a[j + 1] = ai; + } + } else { + /* + * For case of leftmost part traditional (without a sentinel) + * insertion sort, optimized for server JVM, is used. + */ + for (int i = left, j = i; i < right; j = ++i) { + long ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == left) { + break; + } + } + a[j + 1] = ai; + } + } + return; + } + + // Inexpensive approximation of length / 7 + int seventh = (length >>> 3) + (length >>> 6) + 1; + + /* + * Sort five evenly spaced elements around (and including) the + * center element in the range. These elements will be used for + * pivot selection as described below. The choice for spacing + * these elements was empirically determined to work well on + * a wide variety of inputs. + */ int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + int e2 = e3 - seventh; + int e1 = e2 - seventh; + int e4 = e3 + seventh; + int e5 = e4 + seventh; - // Sort these elements using a 5-element sorting network - long ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + // Sort these elements using insertion sort + if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; } - if (ae1 > ae2) { long t = ae1; ae1 = ae2; ae2 = t; } - if (ae4 > ae5) { long t = ae4; ae4 = ae5; ae5 = t; } - if (ae1 > ae3) { long t = ae1; ae1 = ae3; ae3 = t; } - if (ae2 > ae3) { long t = ae2; ae2 = ae3; ae3 = t; } - if (ae1 > ae4) { long t = ae1; ae1 = ae4; ae4 = t; } - if (ae3 > ae4) { long t = ae3; ae3 = ae4; ae4 = t; } - if (ae2 > ae5) { long t = ae2; ae2 = ae5; ae5 = t; } - if (ae2 > ae3) { long t = ae2; ae2 = ae3; ae3 = t; } - if (ae4 > ae5) { long t = ae4; ae4 = ae5; ae5 = t; } - - a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + if (a[e3] < a[e2]) { long t = a[e3]; a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + if (a[e4] < a[e3]) { long t = a[e4]; a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t; + if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + } /* * Use the second and fourth of the five sorted elements as pivots. * These values are inexpensive approximations of the first and * second terciles of the array. Note that pivot1 <= pivot2. - * - * The pivots are stored in local variables, and the first and - * the last of the elements to be sorted are moved to the locations - * formerly occupied by the pivots. When partitioning is complete, - * the pivots are swapped back into their final positions, and - * excluded from subsequent sorting. */ - long pivot1 = ae2; a[e2] = a[left]; - long pivot2 = ae4; a[e4] = a[right]; + long pivot1 = a[e2]; + long pivot2 = a[e4]; // Pointers - int less = left + 1; // The index of first element of center part - int great = right - 1; // The index before first element of right part + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 != pivot2) { + /* + * The first and the last elements to be sorted are moved to the + * locations formerly occupied by the pivots. When partitioning + * is complete, the pivots are swapped back into their final + * positions, and excluded from subsequent sorting. + */ + a[e2] = a[left]; + a[e4] = a[right]; - if (pivotsDiffer) { + /* + * Skip elements, which are less or greater than pivot values. + */ + while (a[++less] < pivot1); + while (a[--great] > pivot2); + /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -472,16 +560,14 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ outer: for (int k = less; k <= great; k++) { long ak = a[k]; if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; } else if (ak > pivot2) { // Move a[k] to right part while (a[great] > pivot2) { @@ -491,26 +577,107 @@ } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // pivot1 <= a[great] <= pivot2 a[k] = a[great]; - a[great--] = ak; + } + a[great] = ak; + great--; + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivots + sort(a, left, less - 2, leftmost); + sort(a, great + 2, right, false); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (less < e1 && e5 < great) { + /* + * Skip elements, which are equal to pivot values. + */ + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + + /* + * Partitioning: + * + * left part center part right part + * +----------------------------------------------------------+ + * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | + * +----------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (*, less) == pivot1 + * pivot1 < all in [less, k) < pivot2 + * all in (great, *) == pivot2 + * + * Pointer k is the first index of ?-part. + */ + outer: + for (int k = less; k <= great; k++) { + long ak = a[k]; + if (ak == pivot1) { // Move a[k] to left part + a[k] = a[less]; + a[less] = ak; + less++; + } else if (ak == pivot2) { // Move a[k] to right part + while (a[great] == pivot2) { + if (great-- == k) { + break outer; + } + } + if (a[great] == pivot1) { + a[k] = a[less]; + /* + * Even though a[great] equals to pivot1, the + * assignment a[less] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point zeros + * of different signs. Therefore in float and + * double sorting methods we have to use more + * accurate assignment a[less] = a[great]. + */ + a[less] = pivot1; + less++; + } else { // pivot1 < a[great] < pivot2 + a[k] = a[great]; + } + a[great] = ak; + great--; } } } + + // Sort center part recursively + sort(a, less, great, false); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * - * left part center part right part - * +----------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +----------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +-------------------------------------------------+ + * | < pivot | == pivot | ? | > pivot | + * +-------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -518,20 +685,19 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ - for (int k = less; k <= great; k++) { - long ak = a[k]; - if (ak == pivot1) { + for (int k = left; k <= great; k++) { + if (a[k] == pivot1) { continue; } + long ak = a[k]; + if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } else { // a[k] > pivot1 - Move a[k] to right part /* * We know that pivot1 == a[e3] == pivot2. Thus, we know * that great will still be >= k when the following loop @@ -539,92 +705,33 @@ * In other words, a[e3] acts as a sentinel for great. */ while (a[great] > pivot1) { + // assert great > k; great--; } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // a[great] == pivot1 + /* + * Even though a[great] equals to pivot1, the + * assignment a[k] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point + * zeros of different signs. Therefore in float + * and double sorting methods we have to use + * more accurate assignment a[k] = a[great]. + */ a[k] = pivot1; - a[great--] = ak; } + a[great] = ak; + great--; } } - } - - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivot values - doSort(a, left, less - 2); - doSort(a, great + 2, right); - - /* - * If pivot1 == pivot2, all elements from center - * part are equal and, therefore, already sorted - */ - if (!pivotsDiffer) { - return; - } - - /* - * If center part is too large (comprises > 2/3 of the array), - * swap internal pivot values to ends - */ - if (less < e1 && great > e5) { - while (a[less] == pivot1) { - less++; - } - while (a[great] == pivot2) { - great--; - } - /* - * Partitioning: - * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 - * - * Pointer k is the first index of ?-part - */ - outer: - for (int k = less; k <= great; k++) { - long ak = a[k]; - if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] == pivot1) { - a[k] = a[less]; - a[less++] = pivot1; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great--] = pivot2; - } else if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less++] = pivot1; - } - } + // Sort left and right parts recursively + sort(a, left, less - 1, leftmost); + sort(a, great + 1, right, false); } - - // Sort center part recursively, excluding known pivot values - doSort(a, less, great); } /** @@ -633,7 +740,11 @@ * @param a the array to be sorted */ public static void sort(short[] a) { - doSort(a, 0, a.length - 1); + if (a.length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + countingSort(a, 0, a.length - 1); + } else { + sort(a, 0, a.length - 1, true); + } } /** @@ -651,115 +762,166 @@ */ public static void sort(short[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + + if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + countingSort(a, fromIndex, toIndex - 1); + } else { + sort(a, fromIndex, toIndex - 1, true); + } } /** The number of distinct short values. */ private static final int NUM_SHORT_VALUES = 1 << 16; /** - * Sorts the specified range of the array into ascending order. This - * method differs from the public {@code sort} method in that the - * {@code right} index is inclusive, and it does no range checking on - * {@code left} or {@code right}. - * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - */ - private static void doSort(short[] a, int left, int right) { - // Use insertion sort on tiny arrays - if (right - left + 1 < INSERTION_SORT_THRESHOLD) { - for (int i = left + 1; i <= right; i++) { - short ai = a[i]; - int j; - for (j = i - 1; j >= left && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { - // Use counting sort on huge arrays - int[] count = new int[NUM_SHORT_VALUES]; - - for (int i = left; i <= right; i++) { - count[a[i] - Short.MIN_VALUE]++; - } - for (int i = 0, k = left; i < count.length && k <= right; i++) { - short value = (short) (i + Short.MIN_VALUE); - - for (int s = count[i]; s > 0; s--) { - a[k++] = value; - } - } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); - } - } - - /** - * Sorts the specified range of the array into ascending order by the - * Dual-Pivot Quicksort algorithm. + * Sorts the specified range of the array by counting sort. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted */ - private static void dualPivotQuicksort(short[] a, int left, int right) { - // Compute indices of five evenly spaced elements - int sixth = (right - left + 1) / 6; - int e1 = left + sixth; - int e5 = right - sixth; - int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + private static void countingSort(short[] a, int left, int right) { + int[] count = new int[NUM_SHORT_VALUES]; + + for (int i = left; i <= right; i++) { + count[a[i] - Short.MIN_VALUE]++; + } + for (int i = NUM_SHORT_VALUES - 1, k = right; k >= left; i--) { + while (count[i] == 0) { + i--; + } + short value = (short) (i + Short.MIN_VALUE); + int s = count[i]; - // Sort these elements using a 5-element sorting network - short ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + do { + a[k--] = value; + } while (--s > 0); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. This method differs from the public + * {@code sort} method in that the {@code right} index is inclusive, + * it does no range checking on {@code left} or {@code right}, and has + * boolean flag whether insertion sort with sentinel is used or not. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + * @param leftmost indicates if the part is the most left in the range + */ + private static void sort(short[] a, int left, int right,boolean leftmost) { + int length = right - left + 1; - if (ae1 > ae2) { short t = ae1; ae1 = ae2; ae2 = t; } - if (ae4 > ae5) { short t = ae4; ae4 = ae5; ae5 = t; } - if (ae1 > ae3) { short t = ae1; ae1 = ae3; ae3 = t; } - if (ae2 > ae3) { short t = ae2; ae2 = ae3; ae3 = t; } - if (ae1 > ae4) { short t = ae1; ae1 = ae4; ae4 = t; } - if (ae3 > ae4) { short t = ae3; ae3 = ae4; ae4 = t; } - if (ae2 > ae5) { short t = ae2; ae2 = ae5; ae5 = t; } - if (ae2 > ae3) { short t = ae2; ae2 = ae3; ae3 = t; } - if (ae4 > ae5) { short t = ae4; ae4 = ae5; ae5 = t; } + // Use insertion sort on tiny arrays + if (length < INSERTION_SORT_THRESHOLD) { + if (!leftmost) { + /* + * Every element in adjoining part plays the role + * of sentinel, therefore this allows us to avoid + * the j >= left check on each iteration. + */ + for (int j, i = left + 1; i <= right; i++) { + short ai = a[i]; + for (j = i - 1; ai < a[j]; j--) { + // assert j >= left; + a[j + 1] = a[j]; + } + a[j + 1] = ai; + } + } else { + /* + * For case of leftmost part traditional (without a sentinel) + * insertion sort, optimized for server JVM, is used. + */ + for (int i = left, j = i; i < right; j = ++i) { + short ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == left) { + break; + } + } + a[j + 1] = ai; + } + } + return; + } - a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + // Inexpensive approximation of length / 7 + int seventh = (length >>> 3) + (length >>> 6) + 1; + + /* + * Sort five evenly spaced elements around (and including) the + * center element in the range. These elements will be used for + * pivot selection as described below. The choice for spacing + * these elements was empirically determined to work well on + * a wide variety of inputs. + */ + int e3 = (left + right) >>> 1; // The midpoint + int e2 = e3 - seventh; + int e1 = e2 - seventh; + int e4 = e3 + seventh; + int e5 = e4 + seventh; + + // Sort these elements using insertion sort + if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + + if (a[e3] < a[e2]) { short t = a[e3]; a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + if (a[e4] < a[e3]) { short t = a[e4]; a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t; + if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + } /* * Use the second and fourth of the five sorted elements as pivots. * These values are inexpensive approximations of the first and * second terciles of the array. Note that pivot1 <= pivot2. - * - * The pivots are stored in local variables, and the first and - * the last of the elements to be sorted are moved to the locations - * formerly occupied by the pivots. When partitioning is complete, - * the pivots are swapped back into their final positions, and - * excluded from subsequent sorting. */ - short pivot1 = ae2; a[e2] = a[left]; - short pivot2 = ae4; a[e4] = a[right]; + short pivot1 = a[e2]; + short pivot2 = a[e4]; // Pointers - int less = left + 1; // The index of first element of center part - int great = right - 1; // The index before first element of right part + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 != pivot2) { + /* + * The first and the last elements to be sorted are moved to the + * locations formerly occupied by the pivots. When partitioning + * is complete, the pivots are swapped back into their final + * positions, and excluded from subsequent sorting. + */ + a[e2] = a[left]; + a[e4] = a[right]; - if (pivotsDiffer) { + /* + * Skip elements, which are less or greater than pivot values. + */ + while (a[++less] < pivot1); + while (a[--great] > pivot2); + /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -767,16 +929,14 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ outer: for (int k = less; k <= great; k++) { short ak = a[k]; if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; } else if (ak > pivot2) { // Move a[k] to right part while (a[great] > pivot2) { @@ -786,26 +946,107 @@ } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // pivot1 <= a[great] <= pivot2 a[k] = a[great]; - a[great--] = ak; + } + a[great] = ak; + great--; + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivots + sort(a, left, less - 2, leftmost); + sort(a, great + 2, right, false); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (less < e1 && e5 < great) { + /* + * Skip elements, which are equal to pivot values. + */ + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + + /* + * Partitioning: + * + * left part center part right part + * +----------------------------------------------------------+ + * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | + * +----------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (*, less) == pivot1 + * pivot1 < all in [less, k) < pivot2 + * all in (great, *) == pivot2 + * + * Pointer k is the first index of ?-part. + */ + outer: + for (int k = less; k <= great; k++) { + short ak = a[k]; + if (ak == pivot1) { // Move a[k] to left part + a[k] = a[less]; + a[less] = ak; + less++; + } else if (ak == pivot2) { // Move a[k] to right part + while (a[great] == pivot2) { + if (great-- == k) { + break outer; + } + } + if (a[great] == pivot1) { + a[k] = a[less]; + /* + * Even though a[great] equals to pivot1, the + * assignment a[less] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point zeros + * of different signs. Therefore in float and + * double sorting methods we have to use more + * accurate assignment a[less] = a[great]. + */ + a[less] = pivot1; + less++; + } else { // pivot1 < a[great] < pivot2 + a[k] = a[great]; + } + a[great] = ak; + great--; } } } + + // Sort center part recursively + sort(a, less, great, false); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * - * left part center part right part - * +----------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +----------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +-------------------------------------------------+ + * | < pivot | == pivot | ? | > pivot | + * +-------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -813,20 +1054,19 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ - for (int k = less; k <= great; k++) { - short ak = a[k]; - if (ak == pivot1) { + for (int k = left; k <= great; k++) { + if (a[k] == pivot1) { continue; } + short ak = a[k]; + if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } else { // a[k] > pivot1 - Move a[k] to right part /* * We know that pivot1 == a[e3] == pivot2. Thus, we know * that great will still be >= k when the following loop @@ -834,92 +1074,33 @@ * In other words, a[e3] acts as a sentinel for great. */ while (a[great] > pivot1) { + // assert great > k; great--; } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // a[great] == pivot1 + /* + * Even though a[great] equals to pivot1, the + * assignment a[k] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point + * zeros of different signs. Therefore in float + * and double sorting methods we have to use + * more accurate assignment a[k] = a[great]. + */ a[k] = pivot1; - a[great--] = ak; } + a[great] = ak; + great--; } } - } - - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivot values - doSort(a, left, less - 2); - doSort(a, great + 2, right); - - /* - * If pivot1 == pivot2, all elements from center - * part are equal and, therefore, already sorted - */ - if (!pivotsDiffer) { - return; - } - - /* - * If center part is too large (comprises > 2/3 of the array), - * swap internal pivot values to ends - */ - if (less < e1 && great > e5) { - while (a[less] == pivot1) { - less++; - } - while (a[great] == pivot2) { - great--; - } - /* - * Partitioning: - * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 - * - * Pointer k is the first index of ?-part - */ - outer: - for (int k = less; k <= great; k++) { - short ak = a[k]; - if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] == pivot1) { - a[k] = a[less]; - a[less++] = pivot1; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great--] = pivot2; - } else if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less++] = pivot1; - } - } + // Sort left and right parts recursively + sort(a, left, less - 1, leftmost); + sort(a, great + 1, right, false); } - - // Sort center part recursively, excluding known pivot values - doSort(a, less, great); } /** @@ -928,7 +1109,11 @@ * @param a the array to be sorted */ public static void sort(char[] a) { - doSort(a, 0, a.length - 1); + if (a.length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + countingSort(a, 0, a.length - 1); + } else { + sort(a, 0, a.length - 1, true); + } } /** @@ -946,113 +1131,166 @@ */ public static void sort(char[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + + if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + countingSort(a, fromIndex, toIndex - 1); + } else { + sort(a, fromIndex, toIndex - 1, true); + } } /** The number of distinct char values. */ private static final int NUM_CHAR_VALUES = 1 << 16; /** - * Sorts the specified range of the array into ascending order. This - * method differs from the public {@code sort} method in that the - * {@code right} index is inclusive, and it does no range checking on - * {@code left} or {@code right}. - * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - */ - private static void doSort(char[] a, int left, int right) { - // Use insertion sort on tiny arrays - if (right - left + 1 < INSERTION_SORT_THRESHOLD) { - for (int i = left + 1; i <= right; i++) { - char ai = a[i]; - int j; - for (j = i - 1; j >= left && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { - // Use counting sort on huge arrays - int[] count = new int[NUM_CHAR_VALUES]; - - for (int i = left; i <= right; i++) { - count[a[i]]++; - } - for (int i = 0, k = left; i < count.length && k <= right; i++) { - for (int s = count[i]; s > 0; s--) { - a[k++] = (char) i; - } - } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); - } - } - - /** - * Sorts the specified range of the array into ascending order by the - * Dual-Pivot Quicksort algorithm. + * Sorts the specified range of the array by counting sort. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted */ - private static void dualPivotQuicksort(char[] a, int left, int right) { - // Compute indices of five evenly spaced elements - int sixth = (right - left + 1) / 6; - int e1 = left + sixth; - int e5 = right - sixth; - int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + private static void countingSort(char[] a, int left, int right) { + int[] count = new int[NUM_CHAR_VALUES]; + + for (int i = left; i <= right; i++) { + count[a[i]]++; + } + for (int i = 0, k = left; k <= right; i++) { + while (count[i] == 0) { + i++; + } + char value = (char) i; + int s = count[i]; - // Sort these elements using a 5-element sorting network - char ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + do { + a[k++] = value; + } while (--s > 0); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. This method differs from the public + * {@code sort} method in that the {@code right} index is inclusive, + * it does no range checking on {@code left} or {@code right}, and has + * boolean flag whether insertion sort with sentinel is used or not. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + * @param leftmost indicates if the part is the most left in the range + */ + private static void sort(char[] a, int left, int right, boolean leftmost) { + int length = right - left + 1; - if (ae1 > ae2) { char t = ae1; ae1 = ae2; ae2 = t; } - if (ae4 > ae5) { char t = ae4; ae4 = ae5; ae5 = t; } - if (ae1 > ae3) { char t = ae1; ae1 = ae3; ae3 = t; } - if (ae2 > ae3) { char t = ae2; ae2 = ae3; ae3 = t; } - if (ae1 > ae4) { char t = ae1; ae1 = ae4; ae4 = t; } - if (ae3 > ae4) { char t = ae3; ae3 = ae4; ae4 = t; } - if (ae2 > ae5) { char t = ae2; ae2 = ae5; ae5 = t; } - if (ae2 > ae3) { char t = ae2; ae2 = ae3; ae3 = t; } - if (ae4 > ae5) { char t = ae4; ae4 = ae5; ae5 = t; } + // Use insertion sort on tiny arrays + if (length < INSERTION_SORT_THRESHOLD) { + if (!leftmost) { + /* + * Every element in adjoining part plays the role + * of sentinel, therefore this allows us to avoid + * the j >= left check on each iteration. + */ + for (int j, i = left + 1; i <= right; i++) { + char ai = a[i]; + for (j = i - 1; ai < a[j]; j--) { + // assert j >= left; + a[j + 1] = a[j]; + } + a[j + 1] = ai; + } + } else { + /* + * For case of leftmost part traditional (without a sentinel) + * insertion sort, optimized for server JVM, is used. + */ + for (int i = left, j = i; i < right; j = ++i) { + char ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == left) { + break; + } + } + a[j + 1] = ai; + } + } + return; + } - a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + // Inexpensive approximation of length / 7 + int seventh = (length >>> 3) + (length >>> 6) + 1; + + /* + * Sort five evenly spaced elements around (and including) the + * center element in the range. These elements will be used for + * pivot selection as described below. The choice for spacing + * these elements was empirically determined to work well on + * a wide variety of inputs. + */ + int e3 = (left + right) >>> 1; // The midpoint + int e2 = e3 - seventh; + int e1 = e2 - seventh; + int e4 = e3 + seventh; + int e5 = e4 + seventh; + + // Sort these elements using insertion sort + if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + + if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t; + if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + } /* * Use the second and fourth of the five sorted elements as pivots. * These values are inexpensive approximations of the first and * second terciles of the array. Note that pivot1 <= pivot2. - * - * The pivots are stored in local variables, and the first and - * the last of the elements to be sorted are moved to the locations - * formerly occupied by the pivots. When partitioning is complete, - * the pivots are swapped back into their final positions, and - * excluded from subsequent sorting. */ - char pivot1 = ae2; a[e2] = a[left]; - char pivot2 = ae4; a[e4] = a[right]; + char pivot1 = a[e2]; + char pivot2 = a[e4]; // Pointers - int less = left + 1; // The index of first element of center part - int great = right - 1; // The index before first element of right part + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 != pivot2) { + /* + * The first and the last elements to be sorted are moved to the + * locations formerly occupied by the pivots. When partitioning + * is complete, the pivots are swapped back into their final + * positions, and excluded from subsequent sorting. + */ + a[e2] = a[left]; + a[e4] = a[right]; - if (pivotsDiffer) { + /* + * Skip elements, which are less or greater than pivot values. + */ + while (a[++less] < pivot1); + while (a[--great] > pivot2); + /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -1060,16 +1298,14 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ outer: for (int k = less; k <= great; k++) { char ak = a[k]; if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; } else if (ak > pivot2) { // Move a[k] to right part while (a[great] > pivot2) { @@ -1079,26 +1315,107 @@ } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // pivot1 <= a[great] <= pivot2 a[k] = a[great]; - a[great--] = ak; + } + a[great] = ak; + great--; + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivots + sort(a, left, less - 2, leftmost); + sort(a, great + 2, right, false); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (less < e1 && e5 < great) { + /* + * Skip elements, which are equal to pivot values. + */ + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + + /* + * Partitioning: + * + * left part center part right part + * +----------------------------------------------------------+ + * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | + * +----------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (*, less) == pivot1 + * pivot1 < all in [less, k) < pivot2 + * all in (great, *) == pivot2 + * + * Pointer k is the first index of ?-part. + */ + outer: + for (int k = less; k <= great; k++) { + char ak = a[k]; + if (ak == pivot1) { // Move a[k] to left part + a[k] = a[less]; + a[less] = ak; + less++; + } else if (ak == pivot2) { // Move a[k] to right part + while (a[great] == pivot2) { + if (great-- == k) { + break outer; + } + } + if (a[great] == pivot1) { + a[k] = a[less]; + /* + * Even though a[great] equals to pivot1, the + * assignment a[less] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point zeros + * of different signs. Therefore in float and + * double sorting methods we have to use more + * accurate assignment a[less] = a[great]. + */ + a[less] = pivot1; + less++; + } else { // pivot1 < a[great] < pivot2 + a[k] = a[great]; + } + a[great] = ak; + great--; } } } + + // Sort center part recursively + sort(a, less, great, false); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * - * left part center part right part - * +----------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +----------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +-------------------------------------------------+ + * | < pivot | == pivot | ? | > pivot | + * +-------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -1106,20 +1423,19 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ - for (int k = less; k <= great; k++) { - char ak = a[k]; - if (ak == pivot1) { + for (int k = left; k <= great; k++) { + if (a[k] == pivot1) { continue; } + char ak = a[k]; + if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } else { // a[k] > pivot1 - Move a[k] to right part /* * We know that pivot1 == a[e3] == pivot2. Thus, we know * that great will still be >= k when the following loop @@ -1127,92 +1443,33 @@ * In other words, a[e3] acts as a sentinel for great. */ while (a[great] > pivot1) { + // assert great > k; great--; } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // a[great] == pivot1 + /* + * Even though a[great] equals to pivot1, the + * assignment a[k] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point + * zeros of different signs. Therefore in float + * and double sorting methods we have to use + * more accurate assignment a[k] = a[great]. + */ a[k] = pivot1; - a[great--] = ak; } + a[great] = ak; + great--; } } - } - - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivot values - doSort(a, left, less - 2); - doSort(a, great + 2, right); - - /* - * If pivot1 == pivot2, all elements from center - * part are equal and, therefore, already sorted - */ - if (!pivotsDiffer) { - return; - } - - /* - * If center part is too large (comprises > 2/3 of the array), - * swap internal pivot values to ends - */ - if (less < e1 && great > e5) { - while (a[less] == pivot1) { - less++; - } - while (a[great] == pivot2) { - great--; - } - /* - * Partitioning: - * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 - * - * Pointer k is the first index of ?-part - */ - outer: - for (int k = less; k <= great; k++) { - char ak = a[k]; - if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] == pivot1) { - a[k] = a[less]; - a[less++] = pivot1; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great--] = pivot2; - } else if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less++] = pivot1; - } - } + // Sort left and right parts recursively + sort(a, left, less - 1, leftmost); + sort(a, great + 1, right, false); } - - // Sort center part recursively, excluding known pivot values - doSort(a, less, great); } /** @@ -1221,7 +1478,11 @@ * @param a the array to be sorted */ public static void sort(byte[] a) { - doSort(a, 0, a.length - 1); + if (a.length > COUNTING_SORT_THRESHOLD_FOR_BYTE) { + countingSort(a, 0, a.length - 1); + } else { + sort(a, 0, a.length - 1, true); + } } /** @@ -1239,115 +1500,166 @@ */ public static void sort(byte[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + + if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_BYTE) { + countingSort(a, fromIndex, toIndex - 1); + } else { + sort(a, fromIndex, toIndex - 1, true); + } } /** The number of distinct byte values. */ private static final int NUM_BYTE_VALUES = 1 << 8; /** - * Sorts the specified range of the array into ascending order. This - * method differs from the public {@code sort} method in that the - * {@code right} index is inclusive, and it does no range checking on - * {@code left} or {@code right}. - * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - */ - private static void doSort(byte[] a, int left, int right) { - // Use insertion sort on tiny arrays - if (right - left + 1 < INSERTION_SORT_THRESHOLD) { - for (int i = left + 1; i <= right; i++) { - byte ai = a[i]; - int j; - for (j = i - 1; j >= left && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_BYTE) { - // Use counting sort on huge arrays - int[] count = new int[NUM_BYTE_VALUES]; - - for (int i = left; i <= right; i++) { - count[a[i] - Byte.MIN_VALUE]++; - } - for (int i = 0, k = left; i < count.length && k <= right; i++) { - byte value = (byte) (i + Byte.MIN_VALUE); - - for (int s = count[i]; s > 0; s--) { - a[k++] = value; - } - } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); - } - } - - /** - * Sorts the specified range of the array into ascending order by the - * Dual-Pivot Quicksort algorithm. + * Sorts the specified range of the array by counting sort. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted */ - private static void dualPivotQuicksort(byte[] a, int left, int right) { - // Compute indices of five evenly spaced elements - int sixth = (right - left + 1) / 6; - int e1 = left + sixth; - int e5 = right - sixth; - int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + private static void countingSort(byte[] a, int left, int right) { + int[] count = new int[NUM_BYTE_VALUES]; + + for (int i = left; i <= right; i++) { + count[a[i] - Byte.MIN_VALUE]++; + } + for (int i = NUM_BYTE_VALUES - 1, k = right; k >= left; i--) { + while (count[i] == 0) { + i--; + } + byte value = (byte) (i + Byte.MIN_VALUE); + int s = count[i]; - // Sort these elements using a 5-element sorting network - byte ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + do { + a[k--] = value; + } while (--s > 0); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. This method differs from the public + * {@code sort} method in that the {@code right} index is inclusive, + * it does no range checking on {@code left} or {@code right}, and has + * boolean flag whether insertion sort with sentinel is used or not. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + * @param leftmost indicates if the part is the most left in the range + */ + private static void sort(byte[] a, int left, int right, boolean leftmost) { + int length = right - left + 1; - if (ae1 > ae2) { byte t = ae1; ae1 = ae2; ae2 = t; } - if (ae4 > ae5) { byte t = ae4; ae4 = ae5; ae5 = t; } - if (ae1 > ae3) { byte t = ae1; ae1 = ae3; ae3 = t; } - if (ae2 > ae3) { byte t = ae2; ae2 = ae3; ae3 = t; } - if (ae1 > ae4) { byte t = ae1; ae1 = ae4; ae4 = t; } - if (ae3 > ae4) { byte t = ae3; ae3 = ae4; ae4 = t; } - if (ae2 > ae5) { byte t = ae2; ae2 = ae5; ae5 = t; } - if (ae2 > ae3) { byte t = ae2; ae2 = ae3; ae3 = t; } - if (ae4 > ae5) { byte t = ae4; ae4 = ae5; ae5 = t; } + // Use insertion sort on tiny arrays + if (length < INSERTION_SORT_THRESHOLD) { + if (!leftmost) { + /* + * Every element in adjoining part plays the role + * of sentinel, therefore this allows us to avoid + * the j >= left check on each iteration. + */ + for (int j, i = left + 1; i <= right; i++) { + byte ai = a[i]; + for (j = i - 1; ai < a[j]; j--) { + // assert j >= left; + a[j + 1] = a[j]; + } + a[j + 1] = ai; + } + } else { + /* + * For case of leftmost part traditional (without a sentinel) + * insertion sort, optimized for server JVM, is used. + */ + for (int i = left, j = i; i < right; j = ++i) { + byte ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == left) { + break; + } + } + a[j + 1] = ai; + } + } + return; + } - a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + // Inexpensive approximation of length / 7 + int seventh = (length >>> 3) + (length >>> 6) + 1; + + /* + * Sort five evenly spaced elements around (and including) the + * center element in the range. These elements will be used for + * pivot selection as described below. The choice for spacing + * these elements was empirically determined to work well on + * a wide variety of inputs. + */ + int e3 = (left + right) >>> 1; // The midpoint + int e2 = e3 - seventh; + int e1 = e2 - seventh; + int e4 = e3 + seventh; + int e5 = e4 + seventh; + + // Sort these elements using insertion sort + if (a[e2] < a[e1]) { byte t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + + if (a[e3] < a[e2]) { byte t = a[e3]; a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + if (a[e4] < a[e3]) { byte t = a[e4]; a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + if (a[e5] < a[e4]) { byte t = a[e5]; a[e5] = a[e4]; a[e4] = t; + if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + } /* * Use the second and fourth of the five sorted elements as pivots. * These values are inexpensive approximations of the first and * second terciles of the array. Note that pivot1 <= pivot2. - * - * The pivots are stored in local variables, and the first and - * the last of the elements to be sorted are moved to the locations - * formerly occupied by the pivots. When partitioning is complete, - * the pivots are swapped back into their final positions, and - * excluded from subsequent sorting. */ - byte pivot1 = ae2; a[e2] = a[left]; - byte pivot2 = ae4; a[e4] = a[right]; + byte pivot1 = a[e2]; + byte pivot2 = a[e4]; // Pointers - int less = left + 1; // The index of first element of center part - int great = right - 1; // The index before first element of right part + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 != pivot2) { + /* + * The first and the last elements to be sorted are moved to the + * locations formerly occupied by the pivots. When partitioning + * is complete, the pivots are swapped back into their final + * positions, and excluded from subsequent sorting. + */ + a[e2] = a[left]; + a[e4] = a[right]; - if (pivotsDiffer) { + /* + * Skip elements, which are less or greater than pivot values. + */ + while (a[++less] < pivot1); + while (a[--great] > pivot2); + /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -1355,16 +1667,14 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ outer: for (int k = less; k <= great; k++) { byte ak = a[k]; if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; } else if (ak > pivot2) { // Move a[k] to right part while (a[great] > pivot2) { @@ -1374,26 +1684,107 @@ } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // pivot1 <= a[great] <= pivot2 a[k] = a[great]; - a[great--] = ak; + } + a[great] = ak; + great--; + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivots + sort(a, left, less - 2, leftmost); + sort(a, great + 2, right, false); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (less < e1 && e5 < great) { + /* + * Skip elements, which are equal to pivot values. + */ + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + + /* + * Partitioning: + * + * left part center part right part + * +----------------------------------------------------------+ + * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | + * +----------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (*, less) == pivot1 + * pivot1 < all in [less, k) < pivot2 + * all in (great, *) == pivot2 + * + * Pointer k is the first index of ?-part. + */ + outer: + for (int k = less; k <= great; k++) { + byte ak = a[k]; + if (ak == pivot1) { // Move a[k] to left part + a[k] = a[less]; + a[less] = ak; + less++; + } else if (ak == pivot2) { // Move a[k] to right part + while (a[great] == pivot2) { + if (great-- == k) { + break outer; + } + } + if (a[great] == pivot1) { + a[k] = a[less]; + /* + * Even though a[great] equals to pivot1, the + * assignment a[less] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point zeros + * of different signs. Therefore in float and + * double sorting methods we have to use more + * accurate assignment a[less] = a[great]. + */ + a[less] = pivot1; + less++; + } else { // pivot1 < a[great] < pivot2 + a[k] = a[great]; + } + a[great] = ak; + great--; } } } + + // Sort center part recursively + sort(a, less, great, false); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * - * left part center part right part - * +----------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +----------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +-------------------------------------------------+ + * | < pivot | == pivot | ? | > pivot | + * +-------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -1401,20 +1792,19 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ - for (int k = less; k <= great; k++) { - byte ak = a[k]; - if (ak == pivot1) { + for (int k = left; k <= great; k++) { + if (a[k] == pivot1) { continue; } + byte ak = a[k]; + if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } else { // a[k] > pivot1 - Move a[k] to right part /* * We know that pivot1 == a[e3] == pivot2. Thus, we know * that great will still be >= k when the following loop @@ -1422,92 +1812,33 @@ * In other words, a[e3] acts as a sentinel for great. */ while (a[great] > pivot1) { + // assert great > k; great--; } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // a[great] == pivot1 + /* + * Even though a[great] equals to pivot1, the + * assignment a[k] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point + * zeros of different signs. Therefore in float + * and double sorting methods we have to use + * more accurate assignment a[k] = a[great]. + */ a[k] = pivot1; - a[great--] = ak; } + a[great] = ak; + great--; } } - } - - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivot values - doSort(a, left, less - 2); - doSort(a, great + 2, right); - - /* - * If pivot1 == pivot2, all elements from center - * part are equal and, therefore, already sorted - */ - if (!pivotsDiffer) { - return; - } - - /* - * If center part is too large (comprises > 2/3 of the array), - * swap internal pivot values to ends - */ - if (less < e1 && great > e5) { - while (a[less] == pivot1) { - less++; - } - while (a[great] == pivot2) { - great--; - } - /* - * Partitioning: - * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 - * - * Pointer k is the first index of ?-part - */ - outer: - for (int k = less; k <= great; k++) { - byte ak = a[k]; - if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] == pivot1) { - a[k] = a[less]; - a[less++] = pivot1; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great--] = pivot2; - } else if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less++] = pivot1; - } - } + // Sort left and right parts recursively + sort(a, left, less - 1, leftmost); + sort(a, great + 1, right, false); } - - // Sort center part recursively, excluding known pivot values - doSort(a, less, great); } /** @@ -1531,7 +1862,7 @@ * Sorts the specified range of the array into ascending order. The range * to be sorted extends from the index {@code fromIndex}, inclusive, to * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty and the call is a no-op). + * the range to be sorted is empty (and the call is a no-op). * *

    The {@code <} relation does not provide a total order on all float * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} @@ -1565,162 +1896,207 @@ */ private static void sortNegZeroAndNaN(float[] a, int left, int right) { /* - * Phase 1: Count negative zeros and move NaNs to end of array + * Phase 1: Move NaNs to the end of the array. */ - final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f); - int numNegativeZeros = 0; - int n = right; - - for (int k = left; k <= n; k++) { + while (left <= right && Float.isNaN(a[right])) { + right--; + } + for (int k = right - 1; k >= left; k--) { float ak = a[k]; - if (ak == 0.0f && NEGATIVE_ZERO == Float.floatToIntBits(ak)) { - a[k] = 0.0f; - numNegativeZeros++; - } else if (ak != ak) { // i.e., ak is NaN - a[k--] = a[n]; - a[n--] = Float.NaN; + if (ak != ak) { // a[k] is NaN + a[k] = a[right]; + a[right] = ak; + right--; } } /* - * Phase 2: Sort everything except NaNs (which are already in place) + * Phase 2: Sort everything except NaNs (which are already in place). */ - doSort(a, left, n); + sort(a, left, right, true); /* - * Phase 3: Turn positive zeros back into negative zeros as appropriate + * Phase 3: Place negative zeros before positive zeros. */ - if (numNegativeZeros == 0) { - return; - } - - // Find first zero element - int zeroIndex = findAnyZero(a, left, n); - - for (int i = zeroIndex - 1; i >= left && a[i] == 0.0f; i--) { - zeroIndex = i; - } + int hi = right; - // Turn the right number of positive zeros back into negative zeros - for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) { - a[i] = -0.0f; - } - } - - /** - * Returns the index of some zero element in the specified range via - * binary search. The range is assumed to be sorted, and must contain - * at least one zero. - * - * @param a the array to be searched - * @param low the index of the first element, inclusive, to be searched - * @param high the index of the last element, inclusive, to be searched - */ - private static int findAnyZero(float[] a, int low, int high) { - while (true) { - int middle = (low + high) >>> 1; + /* + * Search first zero, or first positive, or last negative element. + */ + while (left < hi) { + int middle = (left + hi) >>> 1; float middleValue = a[middle]; if (middleValue < 0.0f) { - low = middle + 1; - } else if (middleValue > 0.0f) { - high = middle - 1; - } else { // middleValue == 0.0f - return middle; + left = middle + 1; + } else { + hi = middle; + } + } + + /* + * Skip the last negative value (if any) or all leading negative zeros. + */ + while (left <= right && Float.floatToRawIntBits(a[left]) < 0) { + left++; + } + + /* + * Move negative zeros to the beginning of the sub-range. + * + * Partitioning: + * + * +---------------------------------------------------+ + * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | + * +---------------------------------------------------+ + * ^ ^ ^ + * | | | + * left p k + * + * Invariants: + * + * all in (*, left) < 0.0 + * all in [left, p) == -0.0 + * all in [p, k) == 0.0 + * all in [k, right] >= 0.0 + * + * Pointer k is the first index of ?-part. + */ + for (int k = left + 1, p = left; k <= right; k++) { + float ak = a[k]; + if (ak != 0.0f) { + break; + } + if (Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f + a[k] = 0.0f; + a[p++] = -0.0f; } } } /** - * Sorts the specified range of the array into ascending order. This - * method differs from the public {@code sort} method in three ways: - * {@code right} index is inclusive, it does no range checking on - * {@code left} or {@code right}, and it does not handle negative - * zeros or NaNs in the array. - * - * @param a the array to be sorted, which must not contain -0.0f or NaN - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - */ - private static void doSort(float[] a, int left, int right) { - // Use insertion sort on tiny arrays - if (right - left + 1 < INSERTION_SORT_THRESHOLD) { - for (int i = left + 1; i <= right; i++) { - float ai = a[i]; - int j; - for (j = i - 1; j >= left && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); - } - } - - /** * Sorts the specified range of the array into ascending order by the - * Dual-Pivot Quicksort algorithm. + * Dual-Pivot Quicksort algorithm. This method differs from the public + * {@code sort} method in that the {@code right} index is inclusive, + * it does no range checking on {@code left} or {@code right}, and has + * boolean flag whether insertion sort with sentinel is used or not. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param leftmost indicates if the part is the most left in the range */ - private static void dualPivotQuicksort(float[] a, int left, int right) { - // Compute indices of five evenly spaced elements - int sixth = (right - left + 1) / 6; - int e1 = left + sixth; - int e5 = right - sixth; - int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + private static void sort(float[] a, int left, int right,boolean leftmost) { + int length = right - left + 1; - // Sort these elements using a 5-element sorting network - float ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + // Use insertion sort on tiny arrays + if (length < INSERTION_SORT_THRESHOLD) { + if (!leftmost) { + /* + * Every element in adjoining part plays the role + * of sentinel, therefore this allows us to avoid + * the j >= left check on each iteration. + */ + for (int j, i = left + 1; i <= right; i++) { + float ai = a[i]; + for (j = i - 1; ai < a[j]; j--) { + // assert j >= left; + a[j + 1] = a[j]; + } + a[j + 1] = ai; + } + } else { + /* + * For case of leftmost part traditional (without a sentinel) + * insertion sort, optimized for server JVM, is used. + */ + for (int i = left, j = i; i < right; j = ++i) { + float ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == left) { + break; + } + } + a[j + 1] = ai; + } + } + return; + } - if (ae1 > ae2) { float t = ae1; ae1 = ae2; ae2 = t; } - if (ae4 > ae5) { float t = ae4; ae4 = ae5; ae5 = t; } - if (ae1 > ae3) { float t = ae1; ae1 = ae3; ae3 = t; } - if (ae2 > ae3) { float t = ae2; ae2 = ae3; ae3 = t; } - if (ae1 > ae4) { float t = ae1; ae1 = ae4; ae4 = t; } - if (ae3 > ae4) { float t = ae3; ae3 = ae4; ae4 = t; } - if (ae2 > ae5) { float t = ae2; ae2 = ae5; ae5 = t; } - if (ae2 > ae3) { float t = ae2; ae2 = ae3; ae3 = t; } - if (ae4 > ae5) { float t = ae4; ae4 = ae5; ae5 = t; } + // Inexpensive approximation of length / 7 + int seventh = (length >>> 3) + (length >>> 6) + 1; + + /* + * Sort five evenly spaced elements around (and including) the + * center element in the range. These elements will be used for + * pivot selection as described below. The choice for spacing + * these elements was empirically determined to work well on + * a wide variety of inputs. + */ + int e3 = (left + right) >>> 1; // The midpoint + int e2 = e3 - seventh; + int e1 = e2 - seventh; + int e4 = e3 + seventh; + int e5 = e4 + seventh; - a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + // Sort these elements using insertion sort + if (a[e2] < a[e1]) { float t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + + if (a[e3] < a[e2]) { float t = a[e3]; a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + if (a[e4] < a[e3]) { float t = a[e4]; a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + if (a[e5] < a[e4]) { float t = a[e5]; a[e5] = a[e4]; a[e4] = t; + if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + } /* * Use the second and fourth of the five sorted elements as pivots. * These values are inexpensive approximations of the first and * second terciles of the array. Note that pivot1 <= pivot2. - * - * The pivots are stored in local variables, and the first and - * the last of the elements to be sorted are moved to the locations - * formerly occupied by the pivots. When partitioning is complete, - * the pivots are swapped back into their final positions, and - * excluded from subsequent sorting. */ - float pivot1 = ae2; a[e2] = a[left]; - float pivot2 = ae4; a[e4] = a[right]; + float pivot1 = a[e2]; + float pivot2 = a[e4]; // Pointers - int less = left + 1; // The index of first element of center part - int great = right - 1; // The index before first element of right part + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 != pivot2) { + /* + * The first and the last elements to be sorted are moved to the + * locations formerly occupied by the pivots. When partitioning + * is complete, the pivots are swapped back into their final + * positions, and excluded from subsequent sorting. + */ + a[e2] = a[left]; + a[e4] = a[right]; - if (pivotsDiffer) { + /* + * Skip elements, which are less or greater than pivot values. + */ + while (a[++less] < pivot1); + while (a[--great] > pivot2); + /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -1728,16 +2104,14 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ outer: for (int k = less; k <= great; k++) { float ak = a[k]; if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; } else if (ak > pivot2) { // Move a[k] to right part while (a[great] > pivot2) { @@ -1747,26 +2121,107 @@ } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // pivot1 <= a[great] <= pivot2 a[k] = a[great]; - a[great--] = ak; + } + a[great] = ak; + great--; + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivots + sort(a, left, less - 2, leftmost); + sort(a, great + 2, right, false); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (less < e1 && e5 < great) { + /* + * Skip elements, which are equal to pivot values. + */ + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + + /* + * Partitioning: + * + * left part center part right part + * +----------------------------------------------------------+ + * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | + * +----------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (*, less) == pivot1 + * pivot1 < all in [less, k) < pivot2 + * all in (great, *) == pivot2 + * + * Pointer k is the first index of ?-part. + */ + outer: + for (int k = less; k <= great; k++) { + float ak = a[k]; + if (ak == pivot1) { // Move a[k] to left part + a[k] = a[less]; + a[less] = ak; + less++; + } else if (ak == pivot2) { // Move a[k] to right part + while (a[great] == pivot2) { + if (great-- == k) { + break outer; + } + } + if (a[great] == pivot1) { + a[k] = a[less]; + /* + * Even though a[great] equals to pivot1, the + * assignment a[less] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point zeros + * of different signs. Therefore in float and + * double sorting methods we have to use more + * accurate assignment a[less] = a[great]. + */ + a[less] = a[great]; + less++; + } else { // pivot1 < a[great] < pivot2 + a[k] = a[great]; + } + a[great] = ak; + great--; } } } + + // Sort center part recursively + sort(a, less, great, false); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * - * left part center part right part - * +----------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +----------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +-------------------------------------------------+ + * | < pivot | == pivot | ? | > pivot | + * +-------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -1774,20 +2229,19 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ - for (int k = less; k <= great; k++) { - float ak = a[k]; - if (ak == pivot1) { + for (int k = left; k <= great; k++) { + if (a[k] == pivot1) { continue; } + float ak = a[k]; + if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } else { // a[k] > pivot1 - Move a[k] to right part /* * We know that pivot1 == a[e3] == pivot2. Thus, we know * that great will still be >= k when the following loop @@ -1795,92 +2249,33 @@ * In other words, a[e3] acts as a sentinel for great. */ while (a[great] > pivot1) { + // assert great > k; great--; } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // a[great] == pivot1 - a[k] = pivot1; - a[great--] = ak; + /* + * Even though a[great] equals to pivot1, the + * assignment a[k] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point + * zeros of different signs. Therefore in float + * and double sorting methods we have to use + * more accurate assignment a[k] = a[great]. + */ + a[k] = a[great]; } + a[great] = ak; + great--; } } - } - - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivot values - doSort(a, left, less - 2); - doSort(a, great + 2, right); - - /* - * If pivot1 == pivot2, all elements from center - * part are equal and, therefore, already sorted - */ - if (!pivotsDiffer) { - return; - } - - /* - * If center part is too large (comprises > 2/3 of the array), - * swap internal pivot values to ends - */ - if (less < e1 && great > e5) { - while (a[less] == pivot1) { - less++; - } - while (a[great] == pivot2) { - great--; - } - /* - * Partitioning: - * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 - * - * Pointer k is the first index of ?-part - */ - outer: - for (int k = less; k <= great; k++) { - float ak = a[k]; - if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] == pivot1) { - a[k] = a[less]; - a[less++] = pivot1; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great--] = pivot2; - } else if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less++] = pivot1; - } - } + // Sort left and right parts recursively + sort(a, left, less - 1, leftmost); + sort(a, great + 1, right, false); } - - // Sort center part recursively, excluding known pivot values - doSort(a, less, great); } /** @@ -1938,162 +2333,207 @@ */ private static void sortNegZeroAndNaN(double[] a, int left, int right) { /* - * Phase 1: Count negative zeros and move NaNs to end of array + * Phase 1: Move NaNs to the end of the array. */ - final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d); - int numNegativeZeros = 0; - int n = right; - - for (int k = left; k <= n; k++) { + while (left <= right && Double.isNaN(a[right])) { + right--; + } + for (int k = right - 1; k >= left; k--) { double ak = a[k]; - if (ak == 0.0d && NEGATIVE_ZERO == Double.doubleToLongBits(ak)) { - a[k] = 0.0d; - numNegativeZeros++; - } else if (ak != ak) { // i.e., ak is NaN - a[k--] = a[n]; - a[n--] = Double.NaN; + if (ak != ak) { // a[k] is NaN + a[k] = a[right]; + a[right] = ak; + right--; } } /* - * Phase 2: Sort everything except NaNs (which are already in place) + * Phase 2: Sort everything except NaNs (which are already in place). */ - doSort(a, left, n); + sort(a, left, right, true); /* - * Phase 3: Turn positive zeros back into negative zeros as appropriate + * Phase 3: Place negative zeros before positive zeros. */ - if (numNegativeZeros == 0) { - return; - } - - // Find first zero element - int zeroIndex = findAnyZero(a, left, n); - - for (int i = zeroIndex - 1; i >= left && a[i] == 0.0d; i--) { - zeroIndex = i; - } + int hi = right; - // Turn the right number of positive zeros back into negative zeros - for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) { - a[i] = -0.0d; - } - } - - /** - * Returns the index of some zero element in the specified range via - * binary search. The range is assumed to be sorted, and must contain - * at least one zero. - * - * @param a the array to be searched - * @param low the index of the first element, inclusive, to be searched - * @param high the index of the last element, inclusive, to be searched - */ - private static int findAnyZero(double[] a, int low, int high) { - while (true) { - int middle = (low + high) >>> 1; + /* + * Search first zero, or first positive, or last negative element. + */ + while (left < hi) { + int middle = (left + hi) >>> 1; double middleValue = a[middle]; if (middleValue < 0.0d) { - low = middle + 1; - } else if (middleValue > 0.0d) { - high = middle - 1; - } else { // middleValue == 0.0d - return middle; + left = middle + 1; + } else { + hi = middle; + } + } + + /* + * Skip the last negative value (if any) or all leading negative zeros. + */ + while (left <= right && Double.doubleToRawLongBits(a[left]) < 0) { + left++; + } + + /* + * Move negative zeros to the beginning of the sub-range. + * + * Partitioning: + * + * +---------------------------------------------------+ + * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | + * +---------------------------------------------------+ + * ^ ^ ^ + * | | | + * left p k + * + * Invariants: + * + * all in (*, left) < 0.0 + * all in [left, p) == -0.0 + * all in [p, k) == 0.0 + * all in [k, right] >= 0.0 + * + * Pointer k is the first index of ?-part. + */ + for (int k = left + 1, p = left; k <= right; k++) { + double ak = a[k]; + if (ak != 0.0d) { + break; + } + if (Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d + a[k] = 0.0d; + a[p++] = -0.0d; } } } /** - * Sorts the specified range of the array into ascending order. This - * method differs from the public {@code sort} method in three ways: - * {@code right} index is inclusive, it does no range checking on - * {@code left} or {@code right}, and it does not handle negative - * zeros or NaNs in the array. - * - * @param a the array to be sorted, which must not contain -0.0d and NaN - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - */ - private static void doSort(double[] a, int left, int right) { - // Use insertion sort on tiny arrays - if (right - left + 1 < INSERTION_SORT_THRESHOLD) { - for (int i = left + 1; i <= right; i++) { - double ai = a[i]; - int j; - for (j = i - 1; j >= left && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); - } - } - - /** * Sorts the specified range of the array into ascending order by the - * Dual-Pivot Quicksort algorithm. + * Dual-Pivot Quicksort algorithm. This method differs from the public + * {@code sort} method in that the {@code right} index is inclusive, + * it does no range checking on {@code left} or {@code right}, and has + * boolean flag whether insertion sort with sentinel is used or not. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param leftmost indicates if the part is the most left in the range */ - private static void dualPivotQuicksort(double[] a, int left, int right) { - // Compute indices of five evenly spaced elements - int sixth = (right - left + 1) / 6; - int e1 = left + sixth; - int e5 = right - sixth; - int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + private static void sort(double[] a, int left,int right,boolean leftmost) { + int length = right - left + 1; - // Sort these elements using a 5-element sorting network - double ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + // Use insertion sort on tiny arrays + if (length < INSERTION_SORT_THRESHOLD) { + if (!leftmost) { + /* + * Every element in adjoining part plays the role + * of sentinel, therefore this allows us to avoid + * the j >= left check on each iteration. + */ + for (int j, i = left + 1; i <= right; i++) { + double ai = a[i]; + for (j = i - 1; ai < a[j]; j--) { + // assert j >= left; + a[j + 1] = a[j]; + } + a[j + 1] = ai; + } + } else { + /* + * For case of leftmost part traditional (without a sentinel) + * insertion sort, optimized for server JVM, is used. + */ + for (int i = left, j = i; i < right; j = ++i) { + double ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == left) { + break; + } + } + a[j + 1] = ai; + } + } + return; + } - if (ae1 > ae2) { double t = ae1; ae1 = ae2; ae2 = t; } - if (ae4 > ae5) { double t = ae4; ae4 = ae5; ae5 = t; } - if (ae1 > ae3) { double t = ae1; ae1 = ae3; ae3 = t; } - if (ae2 > ae3) { double t = ae2; ae2 = ae3; ae3 = t; } - if (ae1 > ae4) { double t = ae1; ae1 = ae4; ae4 = t; } - if (ae3 > ae4) { double t = ae3; ae3 = ae4; ae4 = t; } - if (ae2 > ae5) { double t = ae2; ae2 = ae5; ae5 = t; } - if (ae2 > ae3) { double t = ae2; ae2 = ae3; ae3 = t; } - if (ae4 > ae5) { double t = ae4; ae4 = ae5; ae5 = t; } + // Inexpensive approximation of length / 7 + int seventh = (length >>> 3) + (length >>> 6) + 1; + + /* + * Sort five evenly spaced elements around (and including) the + * center element in the range. These elements will be used for + * pivot selection as described below. The choice for spacing + * these elements was empirically determined to work well on + * a wide variety of inputs. + */ + int e3 = (left + right) >>> 1; // The midpoint + int e2 = e3 - seventh; + int e1 = e2 - seventh; + int e4 = e3 + seventh; + int e5 = e4 + seventh; - a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + // Sort these elements using insertion sort + if (a[e2] < a[e1]) { double t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + + if (a[e3] < a[e2]) { double t = a[e3]; a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + if (a[e4] < a[e3]) { double t = a[e4]; a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + if (a[e5] < a[e4]) { double t = a[e5]; a[e5] = a[e4]; a[e4] = t; + if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; + if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; + if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + } + } /* * Use the second and fourth of the five sorted elements as pivots. * These values are inexpensive approximations of the first and * second terciles of the array. Note that pivot1 <= pivot2. - * - * The pivots are stored in local variables, and the first and - * the last of the elements to be sorted are moved to the locations - * formerly occupied by the pivots. When partitioning is complete, - * the pivots are swapped back into their final positions, and - * excluded from subsequent sorting. */ - double pivot1 = ae2; a[e2] = a[left]; - double pivot2 = ae4; a[e4] = a[right]; + double pivot1 = a[e2]; + double pivot2 = a[e4]; // Pointers - int less = left + 1; // The index of first element of center part - int great = right - 1; // The index before first element of right part + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 != pivot2) { + /* + * The first and the last elements to be sorted are moved to the + * locations formerly occupied by the pivots. When partitioning + * is complete, the pivots are swapped back into their final + * positions, and excluded from subsequent sorting. + */ + a[e2] = a[left]; + a[e4] = a[right]; - if (pivotsDiffer) { + /* + * Skip elements, which are less or greater than pivot values. + */ + while (a[++less] < pivot1); + while (a[--great] > pivot2); + /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -2101,16 +2541,14 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ outer: for (int k = less; k <= great; k++) { double ak = a[k]; if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; } else if (ak > pivot2) { // Move a[k] to right part while (a[great] > pivot2) { @@ -2120,26 +2558,107 @@ } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // pivot1 <= a[great] <= pivot2 a[k] = a[great]; - a[great--] = ak; + } + a[great] = ak; + great--; + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivots + sort(a, left, less - 2, leftmost); + sort(a, great + 2, right, false); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (less < e1 && e5 < great) { + /* + * Skip elements, which are equal to pivot values. + */ + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + + /* + * Partitioning: + * + * left part center part right part + * +----------------------------------------------------------+ + * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | + * +----------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (*, less) == pivot1 + * pivot1 < all in [less, k) < pivot2 + * all in (great, *) == pivot2 + * + * Pointer k is the first index of ?-part. + */ + outer: + for (int k = less; k <= great; k++) { + double ak = a[k]; + if (ak == pivot1) { // Move a[k] to left part + a[k] = a[less]; + a[less] = ak; + less++; + } else if (ak == pivot2) { // Move a[k] to right part + while (a[great] == pivot2) { + if (great-- == k) { + break outer; + } + } + if (a[great] == pivot1) { + a[k] = a[less]; + /* + * Even though a[great] equals to pivot1, the + * assignment a[less] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point zeros + * of different signs. Therefore in float and + * double sorting methods we have to use more + * accurate assignment a[less] = a[great]. + */ + a[less] = a[great]; + less++; + } else { // pivot1 < a[great] < pivot2 + a[k] = a[great]; + } + a[great] = ak; + great--; } } } + + // Sort center part recursively + sort(a, less, great, false); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * - * left part center part right part - * +----------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +----------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +-------------------------------------------------+ + * | < pivot | == pivot | ? | > pivot | + * +-------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -2147,20 +2666,19 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of ?-part. */ - for (int k = less; k <= great; k++) { - double ak = a[k]; - if (ak == pivot1) { + for (int k = left; k <= great; k++) { + if (a[k] == pivot1) { continue; } + double ak = a[k]; + if (ak < pivot1) { // Move a[k] to left part - if (k != less) { - a[k] = a[less]; - a[less] = ak; - } + a[k] = a[less]; + a[less] = ak; less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } else { // a[k] > pivot1 - Move a[k] to right part /* * We know that pivot1 == a[e3] == pivot2. Thus, we know * that great will still be >= k when the following loop @@ -2168,102 +2686,43 @@ * In other words, a[e3] acts as a sentinel for great. */ while (a[great] > pivot1) { + // assert great > k; great--; } if (a[great] < pivot1) { a[k] = a[less]; - a[less++] = a[great]; - a[great--] = ak; + a[less] = a[great]; + less++; } else { // a[great] == pivot1 - a[k] = pivot1; - a[great--] = ak; + /* + * Even though a[great] equals to pivot1, the + * assignment a[k] = pivot1 may be incorrect, + * if a[great] and pivot1 are floating-point + * zeros of different signs. Therefore in float + * and double sorting methods we have to use + * more accurate assignment a[k] = a[great]. + */ + a[k] = a[great]; } + a[great] = ak; + great--; } } - } - - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivot values - doSort(a, left, less - 2); - doSort(a, great + 2, right); - - /* - * If pivot1 == pivot2, all elements from center - * part are equal and, therefore, already sorted - */ - if (!pivotsDiffer) { - return; - } - - /* - * If center part is too large (comprises > 2/3 of the array), - * swap internal pivot values to ends - */ - if (less < e1 && great > e5) { - while (a[less] == pivot1) { - less++; - } - while (a[great] == pivot2) { - great--; - } - /* - * Partitioning: - * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 - * - * Pointer k is the first index of ?-part - */ - outer: - for (int k = less; k <= great; k++) { - double ak = a[k]; - if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] == pivot1) { - a[k] = a[less]; - a[less++] = pivot1; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great--] = pivot2; - } else if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less++] = pivot1; - } - } + // Sort left and right parts recursively + sort(a, left, less - 1, leftmost); + sort(a, great + 1, right, false); } - - // Sort center part recursively, excluding known pivot values - doSort(a, less, great); } /** - * Checks that {@code fromIndex} and {@code toIndex} are in - * the range and throws an appropriate exception, if they aren't. + * Checks that {@code fromIndex} and {@code toIndex} are in the range, + * otherwise throws an appropriate exception. */ private static void rangeCheck(int length, int fromIndex, int toIndex) { if (fromIndex > toIndex) { throw new IllegalArgumentException( - "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + "fromIndex: " + fromIndex + " > toIndex: " + toIndex); } if (fromIndex < 0) { throw new ArrayIndexOutOfBoundsException(fromIndex); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/util/Scanner.java --- a/jdk/src/share/classes/java/util/Scanner.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/util/Scanner.java Wed Jul 05 17:18:12 2017 +0200 @@ -343,7 +343,7 @@ * * @since 1.5 */ -public final class Scanner implements Iterator { +public final class Scanner implements Iterator, Closeable { // Internal buffer used to hold input private CharBuffer buf; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/util/logging/LogManager.java --- a/jdk/src/share/classes/java/util/logging/LogManager.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/util/logging/LogManager.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.io.*; import java.util.*; import java.security.*; +import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; @@ -154,10 +155,10 @@ = new PropertyChangeSupport(LogManager.class); private final static Level defaultLevel = Level.INFO; - // Table of known loggers. Maps names to Loggers. - private Hashtable> loggers = - new Hashtable>(); - // Tree of known loggers + // Table of named Loggers that maps names to Loggers. + private Hashtable namedLoggers = + new Hashtable(); + // Tree of named Loggers private LogNode root = new LogNode(null); private Logger rootLogger; @@ -417,6 +418,121 @@ }}); } + + // loggerRefQueue holds LoggerWeakRef objects for Logger objects + // that have been GC'ed. + private final ReferenceQueue loggerRefQueue + = new ReferenceQueue(); + + // Package-level inner class. + // Helper class for managing WeakReferences to Logger objects. + // + // LogManager.namedLoggers + // - has weak references to all named Loggers + // - namedLoggers keeps the LoggerWeakRef objects for the named + // Loggers around until we can deal with the book keeping for + // the named Logger that is being GC'ed. + // LogManager.LogNode.loggerRef + // - has a weak reference to a named Logger + // - the LogNode will also keep the LoggerWeakRef objects for + // the named Loggers around; currently LogNodes never go away. + // Logger.kids + // - has a weak reference to each direct child Logger; this + // includes anonymous and named Loggers + // - anonymous Loggers are always children of the rootLogger + // which is a strong reference; rootLogger.kids keeps the + // LoggerWeakRef objects for the anonymous Loggers around + // until we can deal with the book keeping. + // + final class LoggerWeakRef extends WeakReference { + private String name; // for namedLoggers cleanup + private LogNode node; // for loggerRef cleanup + private WeakReference parentRef; // for kids cleanup + + LoggerWeakRef(Logger logger) { + super(logger, loggerRefQueue); + + name = logger.getName(); // save for namedLoggers cleanup + } + + // dispose of this LoggerWeakRef object + void dispose() { + if (node != null) { + // if we have a LogNode, then we were a named Logger + // so clear namedLoggers weak ref to us + manager.namedLoggers.remove(name); + name = null; // clear our ref to the Logger's name + + node.loggerRef = null; // clear LogNode's weak ref to us + node = null; // clear our ref to LogNode + } + + if (parentRef != null) { + // this LoggerWeakRef has or had a parent Logger + Logger parent = parentRef.get(); + if (parent != null) { + // the parent Logger is still there so clear the + // parent Logger's weak ref to us + parent.removeChildLogger(this); + } + parentRef = null; // clear our weak ref to the parent Logger + } + } + + // set the node field to the specified value + void setNode(LogNode node) { + this.node = node; + } + + // set the parentRef field to the specified value + void setParentRef(WeakReference parentRef) { + this.parentRef = parentRef; + } + } + + // Package-level method. + // Drain some Logger objects that have been GC'ed. + // + // drainLoggerRefQueueBounded() is called by addLogger() below + // and by Logger.getAnonymousLogger(String) so we'll drain up to + // MAX_ITERATIONS GC'ed Loggers for every Logger we add. + // + // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives + // us about a 50/50 mix in increased weak ref counts versus + // decreased weak ref counts in the AnonLoggerWeakRefLeak test. + // Here are stats for cleaning up sets of 400 anonymous Loggers: + // - test duration 1 minute + // - sample size of 125 sets of 400 + // - average: 1.99 ms + // - minimum: 0.57 ms + // - maximum: 25.3 ms + // + // The same config gives us a better decreased weak ref count + // than increased weak ref count in the LoggerWeakRefLeak test. + // Here are stats for cleaning up sets of 400 named Loggers: + // - test duration 2 minutes + // - sample size of 506 sets of 400 + // - average: 0.57 ms + // - minimum: 0.02 ms + // - maximum: 10.9 ms + // + private final static int MAX_ITERATIONS = 400; + final synchronized void drainLoggerRefQueueBounded() { + for (int i = 0; i < MAX_ITERATIONS; i++) { + if (loggerRefQueue == null) { + // haven't finished loading LogManager yet + break; + } + + LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll(); + if (ref == null) { + break; + } + // a Logger object has been GC'ed so clean it up + ref.dispose(); + } + } + /** * Add a named logger. This does nothing and returns false if a logger * with the same name is already registered. @@ -439,13 +555,16 @@ throw new NullPointerException(); } - WeakReference ref = loggers.get(name); + // cleanup some Loggers that have been GC'ed + drainLoggerRefQueueBounded(); + + LoggerWeakRef ref = namedLoggers.get(name); if (ref != null) { if (ref.get() == null) { - // Hashtable holds stale weak reference - // to a logger which has been GC-ed. - // Allow to register new one. - loggers.remove(name); + // It's possible that the Logger was GC'ed after the + // drainLoggerRefQueueBounded() call above so allow + // a new one to be registered. + namedLoggers.remove(name); } else { // We already have a registered logger with the given name. return false; @@ -454,7 +573,8 @@ // We're adding a new logger. // Note that we are creating a weak reference here. - loggers.put(name, new WeakReference(logger)); + ref = new LoggerWeakRef(logger); + namedLoggers.put(name, ref); // Apply any initial level defined for the new logger. Level level = getLevelProperty(name+".level", null); @@ -469,11 +589,11 @@ // Find the new node and its parent. LogNode node = findNode(name); - node.loggerRef = new WeakReference(logger); + node.loggerRef = ref; Logger parent = null; LogNode nodep = node.parent; while (nodep != null) { - WeakReference nodeRef = nodep.loggerRef; + LoggerWeakRef nodeRef = nodep.loggerRef; if (nodeRef != null) { parent = nodeRef.get(); if (parent != null) { @@ -489,6 +609,9 @@ // Walk over the children and tell them we are their new parent. node.walkAndSetParent(logger); + // new LogNode is ready so tell the LoggerWeakRef about it + ref.setNode(node); + return true; } @@ -572,7 +695,7 @@ * @return matching logger or null if none is found */ public synchronized Logger getLogger(String name) { - WeakReference ref = loggers.get(name); + LoggerWeakRef ref = namedLoggers.get(name); if (ref == null) { return null; } @@ -580,7 +703,7 @@ if (logger == null) { // Hashtable holds stale weak reference // to a logger which has been GC-ed. - loggers.remove(name); + namedLoggers.remove(name); } return logger; } @@ -594,7 +717,7 @@ * @return enumeration of logger name strings */ public synchronized Enumeration getLoggerNames() { - return loggers.keys(); + return namedLoggers.keys(); } /** @@ -942,7 +1065,7 @@ // Nested class to represent a node in our tree of named loggers. private static class LogNode { HashMap children; - WeakReference loggerRef; + LoggerWeakRef loggerRef; LogNode parent; LogNode(LogNode parent) { @@ -958,7 +1081,7 @@ Iterator values = children.values().iterator(); while (values.hasNext()) { LogNode node = values.next(); - WeakReference ref = node.loggerRef; + LoggerWeakRef ref = node.loggerRef; Logger logger = (ref == null) ? null : ref.get(); if (logger == null) { node.walkAndSetParent(parent); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/java/util/logging/Logger.java --- a/jdk/src/share/classes/java/util/logging/Logger.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/java/util/logging/Logger.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -183,7 +183,7 @@ // We keep weak references from parents to children, but strong // references from children to parents. private volatile Logger parent; // our nearest parent. - private ArrayList> kids; // WeakReferences to loggers that have us as parent + private ArrayList kids; // WeakReferences to loggers that have us as parent private volatile Level levelObject; private volatile int levelValue; // current effective level value @@ -366,13 +366,8 @@ * * @return a newly created private Logger */ - public static synchronized Logger getAnonymousLogger() { - LogManager manager = LogManager.getLogManager(); - Logger result = new Logger(null, null); - result.anonymous = true; - Logger root = manager.getLogger(""); - result.doSetParent(root); - return result; + public static Logger getAnonymousLogger() { + return getAnonymousLogger(null); } /** @@ -401,6 +396,8 @@ */ public static synchronized Logger getAnonymousLogger(String resourceBundleName) { LogManager manager = LogManager.getLogManager(); + // cleanup some Loggers that have been GC'ed + manager.drainLoggerRefQueueBounded(); Logger result = new Logger(null, resourceBundleName); result.anonymous = true; Logger root = manager.getLogger(""); @@ -1380,14 +1377,18 @@ synchronized (treeLock) { // Remove ourself from any previous parent. + LogManager.LoggerWeakRef ref = null; if (parent != null) { // assert parent.kids != null; - for (Iterator> iter = parent.kids.iterator(); iter.hasNext(); ) { - WeakReference ref = iter.next(); + for (Iterator iter = parent.kids.iterator(); iter.hasNext(); ) { + ref = iter.next(); Logger kid = ref.get(); if (kid == this) { + // ref is used down below to complete the reparenting iter.remove(); break; + } else { + ref = null; } } // We have now removed ourself from our parents' kids. @@ -1396,9 +1397,14 @@ // Set our new parent. parent = newParent; if (parent.kids == null) { - parent.kids = new ArrayList>(2); + parent.kids = new ArrayList(2); } - parent.kids.add(new WeakReference(this)); + if (ref == null) { + // we didn't have a previous parent + ref = manager.new LoggerWeakRef(this); + } + ref.setParentRef(new WeakReference(parent)); + parent.kids.add(ref); // As a result of the reparenting, the effective level // may have changed for us and our children. @@ -1407,6 +1413,21 @@ } } + // Package-level method. + // Remove the weak reference for the specified child Logger from the + // kid list. We should only be called from LoggerWeakRef.dispose(). + final void removeChildLogger(LogManager.LoggerWeakRef child) { + synchronized (treeLock) { + for (Iterator iter = kids.iterator(); iter.hasNext(); ) { + LogManager.LoggerWeakRef ref = iter.next(); + if (ref == child) { + iter.remove(); + return; + } + } + } + } + // Recalculate the effective level for this node and // recursively for our children. @@ -1438,7 +1459,7 @@ // Recursively update the level on each of our kids. if (kids != null) { for (int i = 0; i < kids.size(); i++) { - WeakReference ref = kids.get(i); + LogManager.LoggerWeakRef ref = kids.get(i); Logger kid = ref.get(); if (kid != null) { kid.updateEffectiveLevel(); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/imageio/stream/ImageInputStream.java --- a/jdk/src/share/classes/javax/imageio/stream/ImageInputStream.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/imageio/stream/ImageInputStream.java Wed Jul 05 17:18:12 2017 +0200 @@ -25,6 +25,7 @@ package javax.imageio.stream; +import java.io.Closeable; import java.io.DataInput; import java.io.IOException; import java.nio.ByteOrder; @@ -42,7 +43,7 @@ * @see MemoryCacheImageInputStream * */ -public interface ImageInputStream extends DataInput { +public interface ImageInputStream extends DataInput, Closeable { /** * Sets the desired byte order for future reads of data values diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/sound/midi/MidiDevice.java --- a/jdk/src/share/classes/javax/sound/midi/MidiDevice.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/sound/midi/MidiDevice.java Wed Jul 05 17:18:12 2017 +0200 @@ -107,7 +107,7 @@ * @author Florian Bomers */ -public interface MidiDevice { +public interface MidiDevice extends AutoCloseable { /** diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/sound/midi/Receiver.java --- a/jdk/src/share/classes/javax/sound/midi/Receiver.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/sound/midi/Receiver.java Wed Jul 05 17:18:12 2017 +0200 @@ -38,7 +38,7 @@ * * @author Kara Kytle */ -public interface Receiver { +public interface Receiver extends AutoCloseable { //$$fb 2002-04-12: fix for 4662090: Contradiction in Receiver specification diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/sound/midi/Transmitter.java --- a/jdk/src/share/classes/javax/sound/midi/Transmitter.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/sound/midi/Transmitter.java Wed Jul 05 17:18:12 2017 +0200 @@ -35,7 +35,7 @@ * * @author Kara Kytle */ -public interface Transmitter { +public interface Transmitter extends AutoCloseable { /** diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/sound/sampled/Line.java --- a/jdk/src/share/classes/javax/sound/sampled/Line.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/sound/sampled/Line.java Wed Jul 05 17:18:12 2017 +0200 @@ -70,7 +70,7 @@ * @see LineEvent * @since 1.3 */ -public interface Line { +public interface Line extends AutoCloseable { /** * Obtains the Line.Info object describing this diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/swing/JSplitPane.java --- a/jdk/src/share/classes/javax/swing/JSplitPane.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/swing/JSplitPane.java Wed Jul 05 17:18:12 2017 +0200 @@ -242,19 +242,19 @@ /** * Creates a new JSplitPane configured to arrange the child - * components side-by-side horizontally with no continuous - * layout, using two buttons for the components. + * components side-by-side horizontally, using two buttons for the components. */ public JSplitPane() { - this(JSplitPane.HORIZONTAL_SPLIT, false, - new JButton(UIManager.getString("SplitPane.leftButtonText")), - new JButton(UIManager.getString("SplitPane.rightButtonText"))); + this(JSplitPane.HORIZONTAL_SPLIT, + UIManager.getBoolean("SplitPane.continuousLayout"), + new JButton(UIManager.getString("SplitPane.leftButtonText")), + new JButton(UIManager.getString("SplitPane.rightButtonText"))); } /** * Creates a new JSplitPane configured with the - * specified orientation and no continuous layout. + * specified orientation. * * @param newOrientation JSplitPane.HORIZONTAL_SPLIT or * JSplitPane.VERTICAL_SPLIT @@ -263,7 +263,8 @@ */ @ConstructorProperties({"orientation"}) public JSplitPane(int newOrientation) { - this(newOrientation, false); + this(newOrientation, + UIManager.getBoolean("SplitPane.continuousLayout")); } @@ -287,9 +288,7 @@ /** * Creates a new JSplitPane with the specified - * orientation and - * with the specified components that do not do continuous - * redrawing. + * orientation and the specified components. * * @param newOrientation JSplitPane.HORIZONTAL_SPLIT or * JSplitPane.VERTICAL_SPLIT @@ -307,7 +306,9 @@ public JSplitPane(int newOrientation, Component newLeftComponent, Component newRightComponent){ - this(newOrientation, false, newLeftComponent, newRightComponent); + this(newOrientation, + UIManager.getBoolean("SplitPane.continuousLayout"), + newLeftComponent, newRightComponent); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/swing/JTable.java --- a/jdk/src/share/classes/javax/swing/JTable.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/swing/JTable.java Wed Jul 05 17:18:12 2017 +0200 @@ -1048,7 +1048,7 @@ /** * Returns the horizontal and vertical space between cells. - * The default spacing is (1, 1), which provides room to draw the grid. + * The default spacing is look and feel dependent. * * @return the horizontal and vertical spacing between cells * @see #setIntercellSpacing @@ -1155,7 +1155,7 @@ /** * Returns true if the table draws horizontal lines between cells, false if it - * doesn't. The default is true. + * doesn't. The default value is look and feel dependent. * * @return true if the table draws horizontal lines between cells, false if it * doesn't @@ -1167,7 +1167,7 @@ /** * Returns true if the table draws vertical lines between cells, false if it - * doesn't. The default is true. + * doesn't. The default value is look and feel dependent. * * @return true if the table draws vertical lines between cells, false if it * doesn't diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/swing/JTree.java --- a/jdk/src/share/classes/javax/swing/JTree.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/swing/JTree.java Wed Jul 05 17:18:12 2017 +0200 @@ -1986,20 +1986,17 @@ * true if all nodes in the path are expanded */ public boolean isExpanded(TreePath path) { + if(path == null) return false; - - // Is this node expanded? - Boolean value = expandedState.get(path); - - if(value == null || !value.booleanValue()) - return false; - - // It is, make sure its parent is also expanded. - TreePath parentPath = path.getParentPath(); - - if(parentPath != null) - return isExpanded(parentPath); + Object value; + + do{ + value = expandedState.get(path); + if(value == null || !((Boolean)value).booleanValue()) + return false; + } while( (path=path.getParentPath())!=null ); + return true; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/swing/border/TitledBorder.java --- a/jdk/src/share/classes/javax/swing/border/TitledBorder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/swing/border/TitledBorder.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,22 +24,20 @@ */ package javax.swing.border; -import sun.swing.SwingUtilities2; - +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Rectangle; -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Point; -import java.awt.Toolkit; -import java.awt.Component; -import java.awt.Dimension; +import java.awt.geom.Path2D; import java.beans.ConstructorProperties; - import javax.swing.JComponent; +import javax.swing.JLabel; import javax.swing.UIManager; +import javax.swing.plaf.basic.BasicHTML; /** * A class which implements an arbitrary border @@ -73,40 +71,40 @@ { protected String title; protected Border border; - protected int titlePosition; - protected int titleJustification; - protected Font titleFont; - protected Color titleColor; + protected int titlePosition; + protected int titleJustification; + protected Font titleFont; + protected Color titleColor; - private Point textLoc = new Point(); + private final JLabel label; /** * Use the default vertical orientation for the title text. */ static public final int DEFAULT_POSITION = 0; /** Position the title above the border's top line. */ - static public final int ABOVE_TOP = 1; + static public final int ABOVE_TOP = 1; /** Position the title in the middle of the border's top line. */ - static public final int TOP = 2; + static public final int TOP = 2; /** Position the title below the border's top line. */ - static public final int BELOW_TOP = 3; + static public final int BELOW_TOP = 3; /** Position the title above the border's bottom line. */ - static public final int ABOVE_BOTTOM = 4; + static public final int ABOVE_BOTTOM = 4; /** Position the title in the middle of the border's bottom line. */ - static public final int BOTTOM = 5; + static public final int BOTTOM = 5; /** Position the title below the border's bottom line. */ - static public final int BELOW_BOTTOM = 6; + static public final int BELOW_BOTTOM = 6; /** * Use the default justification for the title text. */ static public final int DEFAULT_JUSTIFICATION = 0; /** Position title text at the left side of the border line. */ - static public final int LEFT = 1; + static public final int LEFT = 1; /** Position title text in the center of the border line. */ - static public final int CENTER = 2; + static public final int CENTER = 2; /** Position title text at the right side of the border line. */ - static public final int RIGHT = 3; + static public final int RIGHT = 3; /** Position title text at the left side of the border line * for left to right orientation, at the right side of the * border line for right to left orientation. @@ -132,7 +130,7 @@ * * @param title the title the border should display */ - public TitledBorder(String title) { + public TitledBorder(String title) { this(null, title, LEADING, DEFAULT_POSITION, null, null); } @@ -142,7 +140,7 @@ * * @param border the border */ - public TitledBorder(Border border) { + public TitledBorder(Border border) { this(border, "", LEADING, DEFAULT_POSITION, null, null); } @@ -167,9 +165,9 @@ * @param titlePosition the position for the title */ public TitledBorder(Border border, - String title, - int titleJustification, - int titlePosition) { + String title, + int titleJustification, + int titlePosition) { this(border, title, titleJustification, titlePosition, null, null); } @@ -185,10 +183,10 @@ * @param titleFont the font for rendering the title */ public TitledBorder(Border border, - String title, - int titleJustification, - int titlePosition, - Font titleFont) { + String title, + int titleJustification, + int titlePosition, + Font titleFont) { this(border, title, titleJustification, titlePosition, titleFont, null); } @@ -207,11 +205,11 @@ */ @ConstructorProperties({"border", "title", "titleJustification", "titlePosition", "titleFont", "titleColor"}) public TitledBorder(Border border, - String title, - int titleJustification, - int titlePosition, - Font titleFont, - Color titleColor) { + String title, + int titleJustification, + int titlePosition, + Font titleFont, + Color titleColor) { this.title = title; this.border = border; this.titleFont = titleFont; @@ -219,6 +217,10 @@ setTitleJustification(titleJustification); setTitlePosition(titlePosition); + + this.label = new JLabel(); + this.label.setOpaque(false); + this.label.putClientProperty(BasicHTML.propertyKey, null); } /** @@ -232,178 +234,111 @@ * @param height the height of the painted border */ public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - - Border border = getBorder(); - - if (getTitle() == null || getTitle().equals("")) { - if (border != null) { - border.paintBorder(c, g, x, y, width, height); - } - return; - } - - Rectangle grooveRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING, - width - (EDGE_SPACING * 2), - height - (EDGE_SPACING * 2)); - Font font = g.getFont(); - Color color = g.getColor(); + Border border = getBorderUI(); + String title = getTitle(); + if ((title != null) && !title.isEmpty()) { + int edge = (border instanceof TitledBorder) ? 0 : EDGE_SPACING; + JLabel label = getLabel(c); + Dimension size = label.getPreferredSize(); + Insets insets = (border != null) + ? border.getBorderInsets(c) + : new Insets(0, 0, 0, 0); - g.setFont(getFont(c)); - - JComponent jc = (c instanceof JComponent) ? (JComponent)c : null; - FontMetrics fm = SwingUtilities2.getFontMetrics(jc, g); - int fontHeight = fm.getHeight(); - int descent = fm.getDescent(); - int ascent = fm.getAscent(); - int diff; - int stringWidth = SwingUtilities2.stringWidth(jc, fm, - getTitle()); - Insets insets; - - if (border != null) { - insets = border.getBorderInsets(c); - } else { - insets = new Insets(0, 0, 0, 0); - } + int borderX = x + edge; + int borderY = y + edge; + int borderW = width - edge - edge; + int borderH = height - edge - edge; - int titlePos = getTitlePosition(); - switch (titlePos) { - case ABOVE_TOP: - diff = ascent + descent + (Math.max(EDGE_SPACING, - TEXT_SPACING*2) - EDGE_SPACING); - grooveRect.y += diff; - grooveRect.height -= diff; - textLoc.y = grooveRect.y - (descent + TEXT_SPACING); - break; - case TOP: - case DEFAULT_POSITION: - diff = Math.max(0, ((ascent/2) + TEXT_SPACING) - EDGE_SPACING); - grooveRect.y += diff; - grooveRect.height -= diff; - textLoc.y = (grooveRect.y - descent) + - (insets.top + ascent + descent)/2; - break; - case BELOW_TOP: - textLoc.y = grooveRect.y + insets.top + ascent + TEXT_SPACING; - break; - case ABOVE_BOTTOM: - textLoc.y = (grooveRect.y + grooveRect.height) - - (insets.bottom + descent + TEXT_SPACING); - break; - case BOTTOM: - grooveRect.height -= fontHeight/2; - textLoc.y = ((grooveRect.y + grooveRect.height) - descent) + - ((ascent + descent) - insets.bottom)/2; - break; - case BELOW_BOTTOM: - grooveRect.height -= fontHeight; - textLoc.y = grooveRect.y + grooveRect.height + ascent + - TEXT_SPACING; - break; - } - - int justification = getTitleJustification(); - if(isLeftToRight(c)) { - if(justification==LEADING || - justification==DEFAULT_JUSTIFICATION) { - justification = LEFT; - } - else if(justification==TRAILING) { - justification = RIGHT; - } - } - else { - if(justification==LEADING || - justification==DEFAULT_JUSTIFICATION) { - justification = RIGHT; + int labelY = y; + int labelH = size.height; + int position = getPosition(); + switch (position) { + case ABOVE_TOP: + insets.left = 0; + insets.right = 0; + borderY += labelH - edge; + borderH -= labelH - edge; + break; + case TOP: + insets.top = edge + insets.top/2 - labelH/2; + if (insets.top < edge) { + borderY -= insets.top; + borderH += insets.top; + } + else { + labelY += insets.top; + } + break; + case BELOW_TOP: + labelY += insets.top + edge; + break; + case ABOVE_BOTTOM: + labelY += height - labelH - insets.bottom - edge; + break; + case BOTTOM: + labelY += height - labelH; + insets.bottom = edge + (insets.bottom - labelH) / 2; + if (insets.bottom < edge) { + borderH += insets.bottom; + } + else { + labelY -= insets.bottom; + } + break; + case BELOW_BOTTOM: + insets.left = 0; + insets.right = 0; + labelY += height - labelH; + borderH -= labelH - edge; + break; } - else if(justification==TRAILING) { - justification = LEFT; - } - } - - switch (justification) { - case LEFT: - textLoc.x = grooveRect.x + TEXT_INSET_H + insets.left; - break; - case RIGHT: - textLoc.x = (grooveRect.x + grooveRect.width) - - (stringWidth + TEXT_INSET_H + insets.right); - break; - case CENTER: - textLoc.x = grooveRect.x + - ((grooveRect.width - stringWidth) / 2); - break; - } + insets.left += edge + TEXT_INSET_H; + insets.right += edge + TEXT_INSET_H; - // If title is positioned in middle of border AND its fontsize - // is greater than the border's thickness, we'll need to paint - // the border in sections to leave space for the component's background - // to show through the title. - // - if (border != null) { - if (((titlePos == TOP || titlePos == DEFAULT_POSITION) && - (grooveRect.y > textLoc.y - ascent)) || - (titlePos == BOTTOM && - (grooveRect.y + grooveRect.height < textLoc.y + descent))) { - - Rectangle clipRect = new Rectangle(); - - // save original clip - Rectangle saveClip = g.getClipBounds(); - - // paint strip left of text - clipRect.setBounds(saveClip); - if (computeIntersection(clipRect, x, y, textLoc.x-1-x, height)) { - g.setClip(clipRect); - border.paintBorder(c, g, grooveRect.x, grooveRect.y, - grooveRect.width, grooveRect.height); - } + int labelX = x; + int labelW = width - insets.left - insets.right; + if (labelW > size.width) { + labelW = size.width; + } + switch (getJustification(c)) { + case LEFT: + labelX += insets.left; + break; + case RIGHT: + labelX += width - insets.right - labelW; + break; + case CENTER: + labelX += (width - labelW) / 2; + break; + } - // paint strip right of text - clipRect.setBounds(saveClip); - if (computeIntersection(clipRect, textLoc.x+stringWidth+1, y, - x+width-(textLoc.x+stringWidth+1), height)) { - g.setClip(clipRect); - border.paintBorder(c, g, grooveRect.x, grooveRect.y, - grooveRect.width, grooveRect.height); + if (border != null) { + if ((position != TOP) && (position != BOTTOM)) { + border.paintBorder(c, g, borderX, borderY, borderW, borderH); } - - if (titlePos == TOP || titlePos == DEFAULT_POSITION) { - // paint strip below text - clipRect.setBounds(saveClip); - if (computeIntersection(clipRect, textLoc.x-1, textLoc.y+descent, - stringWidth+2, y+height-textLoc.y-descent)) { - g.setClip(clipRect); - border.paintBorder(c, g, grooveRect.x, grooveRect.y, - grooveRect.width, grooveRect.height); + else { + Graphics g2 = g.create(); + if (g2 instanceof Graphics2D) { + Graphics2D g2d = (Graphics2D) g2; + Path2D path = new Path2D.Float(); + path.append(new Rectangle(borderX, borderY, borderW, labelY - borderY), false); + path.append(new Rectangle(borderX, labelY, labelX - borderX - TEXT_SPACING, labelH), false); + path.append(new Rectangle(labelX + labelW + TEXT_SPACING, labelY, borderX - labelX + borderW - labelW - TEXT_SPACING, labelH), false); + path.append(new Rectangle(borderX, labelY + labelH, borderW, borderY - labelY + borderH - labelH), false); + g2d.clip(path); } - - } else { // titlePos == BOTTOM - // paint strip above text - clipRect.setBounds(saveClip); - if (computeIntersection(clipRect, textLoc.x-1, y, - stringWidth+2, textLoc.y - ascent - y)) { - g.setClip(clipRect); - border.paintBorder(c, g, grooveRect.x, grooveRect.y, - grooveRect.width, grooveRect.height); - } + border.paintBorder(c, g2, borderX, borderY, borderW, borderH); + g2.dispose(); } - - // restore clip - g.setClip(saveClip); - - } else { - border.paintBorder(c, g, grooveRect.x, grooveRect.y, - grooveRect.width, grooveRect.height); } + g.translate(labelX, labelY); + label.setSize(labelW, labelH); + label.paint(g); + g.translate(-labelX, -labelY); } - - g.setColor(getTitleColor()); - SwingUtilities2.drawString(jc, g, getTitle(), textLoc.x, textLoc.y); - - g.setFont(font); - g.setColor(color); + else if (border != null) { + border.paintBorder(c, g, x, y, width, height); + } } /** @@ -412,69 +347,54 @@ * @param insets the object to be reinitialized */ public Insets getBorderInsets(Component c, Insets insets) { - FontMetrics fm; - int descent = 0; - int ascent = 16; - int height = 16; - - Border border = getBorder(); - if (border != null) { - if (border instanceof AbstractBorder) { - ((AbstractBorder)border).getBorderInsets(c, insets); - } else { - // Can't reuse border insets because the Border interface - // can't be enhanced. - Insets i = border.getBorderInsets(c); - insets.top = i.top; - insets.right = i.right; - insets.bottom = i.bottom; - insets.left = i.left; - } - } else { - insets.left = insets.top = insets.right = insets.bottom = 0; + Border border = getBorderUI(); + if (border == null) { + insets.set(0, 0, 0, 0); + } + else if (border instanceof AbstractBorder) { + AbstractBorder ab = (AbstractBorder) border; + insets = ab.getBorderInsets(c, insets); } - - insets.left += EDGE_SPACING + TEXT_SPACING; - insets.right += EDGE_SPACING + TEXT_SPACING; - insets.top += EDGE_SPACING + TEXT_SPACING; - insets.bottom += EDGE_SPACING + TEXT_SPACING; - - if(c == null || getTitle() == null || getTitle().equals("")) { - return insets; + else { + Insets i = border.getBorderInsets(c); + insets.set(i.top, i.left, i.bottom, i.right); } + String title = getTitle(); + if ((title != null) && !title.isEmpty()) { + int edge = (border instanceof TitledBorder) ? 0 : EDGE_SPACING; + JLabel label = getLabel(c); + Dimension size = label.getPreferredSize(); - Font font = getFont(c); - - fm = c.getFontMetrics(font); - - if(fm != null) { - descent = fm.getDescent(); - ascent = fm.getAscent(); - height = fm.getHeight(); - } - - switch (getTitlePosition()) { - case ABOVE_TOP: - insets.top += ascent + descent - + (Math.max(EDGE_SPACING, TEXT_SPACING*2) - - EDGE_SPACING); - break; - case TOP: - case DEFAULT_POSITION: - insets.top += ascent + descent; - break; - case BELOW_TOP: - insets.top += ascent + descent + TEXT_SPACING; - break; - case ABOVE_BOTTOM: - insets.bottom += ascent + descent + TEXT_SPACING; - break; - case BOTTOM: - insets.bottom += ascent + descent; - break; - case BELOW_BOTTOM: - insets.bottom += height; - break; + switch (getPosition()) { + case ABOVE_TOP: + insets.top += size.height - edge; + break; + case TOP: { + if (insets.top < size.height) { + insets.top = size.height - edge; + } + break; + } + case BELOW_TOP: + insets.top += size.height; + break; + case ABOVE_BOTTOM: + insets.bottom += size.height; + break; + case BOTTOM: { + if (insets.bottom < size.height) { + insets.bottom = size.height - edge; + } + break; + } + case BELOW_BOTTOM: + insets.bottom += size.height - edge; + break; + } + insets.top += edge + TEXT_SPACING; + insets.left += edge + TEXT_SPACING; + insets.right += edge + TEXT_SPACING; + insets.bottom += edge + TEXT_SPACING; } return insets; } @@ -492,41 +412,14 @@ /** * Returns the border of the titled border. */ - public Border getBorder() { - Border b = border; - if (b == null) - b = UIManager.getBorder("TitledBorder.border"); - return b; + public Border getBorder() { + return border; } /** * Returns the title-position of the titled border. */ public int getTitlePosition() { - if (titlePosition == DEFAULT_POSITION) { - Object value = UIManager.get("TitledBorder.position"); - if (value instanceof String) { - String s = (String)value; - if ("ABOVE_TOP".equalsIgnoreCase(s)) { - return ABOVE_TOP; - } else if ("TOP".equalsIgnoreCase(s)) { - return TOP; - } else if ("BELOW_TOP".equalsIgnoreCase(s)) { - return BELOW_TOP; - } else if ("ABOVE_BOTTOM".equalsIgnoreCase(s)) { - return ABOVE_BOTTOM; - } else if ("BOTTOM".equalsIgnoreCase(s)) { - return BOTTOM; - } else if ("BELOW_BOTTOM".equalsIgnoreCase(s)) { - return BELOW_BOTTOM; - } - } else if (value instanceof Integer) { - int i = (Integer)value; - if (i >= 0 && i <= 6) { - return i; - } - } - } return titlePosition; } @@ -539,20 +432,14 @@ * Returns the title-font of the titled border. */ public Font getTitleFont() { - Font f = titleFont; - if (f == null) - f = UIManager.getFont("TitledBorder.font"); - return f; + return titleFont; } /** * Returns the title-color of the titled border. */ public Color getTitleColor() { - Color c = titleColor; - if (c == null) - c = UIManager.getColor("TitledBorder.titleColor"); - return c; + return titleColor; } @@ -576,18 +463,18 @@ */ public void setTitlePosition(int titlePosition) { switch (titlePosition) { - case ABOVE_TOP: - case TOP: - case BELOW_TOP: - case ABOVE_BOTTOM: - case BOTTOM: - case BELOW_BOTTOM: - case DEFAULT_POSITION: + case ABOVE_TOP: + case TOP: + case BELOW_TOP: + case ABOVE_BOTTOM: + case BOTTOM: + case BELOW_BOTTOM: + case DEFAULT_POSITION: this.titlePosition = titlePosition; break; - default: - throw new IllegalArgumentException(titlePosition + - " is not a valid title position."); + default: + throw new IllegalArgumentException(titlePosition + + " is not a valid title position."); } } @@ -624,7 +511,7 @@ * @param titleColor the color for the border title */ public void setTitleColor(Color titleColor) { - this.titleColor = titleColor; + this.titleColor = titleColor; } /** @@ -636,22 +523,18 @@ Insets insets = getBorderInsets(c); Dimension minSize = new Dimension(insets.right+insets.left, insets.top+insets.bottom); - Font font = getFont(c); - FontMetrics fm = c.getFontMetrics(font); - JComponent jc = (c instanceof JComponent) ? (JComponent)c : null; - switch (getTitlePosition()) { - case ABOVE_TOP: - case BELOW_BOTTOM: - minSize.width = Math.max(SwingUtilities2.stringWidth(jc, fm, - getTitle()), minSize.width); - break; - case BELOW_TOP: - case ABOVE_BOTTOM: - case TOP: - case BOTTOM: - case DEFAULT_POSITION: - default: - minSize.width += SwingUtilities2.stringWidth(jc, fm, getTitle()); + String title = getTitle(); + if ((title != null) && !title.isEmpty()) { + JLabel label = getLabel(c); + Dimension size = label.getPreferredSize(); + + int position = getPosition(); + if ((position != ABOVE_TOP) && (position != BELOW_BOTTOM)) { + minSize.width += size.width; + } + else if (minSize.width < size.width) { + minSize.width += size.width; + } } return minSize; } @@ -674,48 +557,36 @@ if (height < 0) { throw new IllegalArgumentException("Height must be >= 0"); } + Border border = getBorderUI(); String title = getTitle(); - if (title != null && !"".equals(title)) { - Font font = getFont(c); - Border border2 = getBorder(); - Insets borderInsets; - if (border2 != null) { - borderInsets = border2.getBorderInsets(c); - } - else { - borderInsets = new Insets(0, 0, 0, 0); - } - FontMetrics fm = c.getFontMetrics(font); - int fontHeight = fm.getHeight(); - int descent = fm.getDescent(); - int ascent = fm.getAscent(); - int y = EDGE_SPACING; - int h = height - EDGE_SPACING * 2; - int diff; - switch (getTitlePosition()) { - case ABOVE_TOP: - diff = ascent + descent + (Math.max(EDGE_SPACING, - TEXT_SPACING * 2) - - EDGE_SPACING); - return y + diff - (descent + TEXT_SPACING); - case TOP: - case DEFAULT_POSITION: - diff = Math.max(0, ((ascent/2) + TEXT_SPACING) - - EDGE_SPACING); - return (y + diff - descent) + - (borderInsets.top + ascent + descent)/2; - case BELOW_TOP: - return y + borderInsets.top + ascent + TEXT_SPACING; - case ABOVE_BOTTOM: - return (y + h) - (borderInsets.bottom + descent + - TEXT_SPACING); - case BOTTOM: - h -= fontHeight / 2; - return ((y + h) - descent) + - ((ascent + descent) - borderInsets.bottom)/2; - case BELOW_BOTTOM: - h -= fontHeight; - return y + h + ascent + TEXT_SPACING; + if ((title != null) && !title.isEmpty()) { + int edge = (border instanceof TitledBorder) ? 0 : EDGE_SPACING; + JLabel label = getLabel(c); + Dimension size = label.getPreferredSize(); + Insets insets = (border != null) + ? border.getBorderInsets(c) + : new Insets(0, 0, 0, 0); + + int baseline = label.getBaseline(size.width, size.height); + switch (getPosition()) { + case ABOVE_TOP: + return baseline; + case TOP: + insets.top = edge + (insets.top - size.height) / 2; + return (insets.top < edge) + ? baseline + : baseline + insets.top; + case BELOW_TOP: + return baseline + insets.top + edge; + case ABOVE_BOTTOM: + return baseline + height - size.height - insets.bottom - edge; + case BOTTOM: + insets.bottom = edge + (insets.bottom - size.height) / 2; + return (insets.bottom < edge) + ? baseline + height - size.height + : baseline + height - size.height + insets.bottom; + case BELOW_BOTTOM: + return baseline + height - size.height; } } return -1; @@ -732,44 +603,111 @@ public Component.BaselineResizeBehavior getBaselineResizeBehavior( Component c) { super.getBaselineResizeBehavior(c); - switch(getTitlePosition()) { - case TitledBorder.ABOVE_TOP: - case TitledBorder.TOP: - case TitledBorder.DEFAULT_POSITION: - case TitledBorder.BELOW_TOP: - return Component.BaselineResizeBehavior.CONSTANT_ASCENT; - case TitledBorder.ABOVE_BOTTOM: - case TitledBorder.BOTTOM: - case TitledBorder.BELOW_BOTTOM: - return JComponent.BaselineResizeBehavior.CONSTANT_DESCENT; + switch (getPosition()) { + case TitledBorder.ABOVE_TOP: + case TitledBorder.TOP: + case TitledBorder.BELOW_TOP: + return Component.BaselineResizeBehavior.CONSTANT_ASCENT; + case TitledBorder.ABOVE_BOTTOM: + case TitledBorder.BOTTOM: + case TitledBorder.BELOW_BOTTOM: + return JComponent.BaselineResizeBehavior.CONSTANT_DESCENT; } return Component.BaselineResizeBehavior.OTHER; } + private Border getBorderUI() { + Border border = getBorder(); + return border != null + ? border + : UIManager.getBorder("TitledBorder.border"); + } + + private int getPosition() { + int position = getTitlePosition(); + if (position != DEFAULT_POSITION) { + return position; + } + Object value = UIManager.get("TitledBorder.position"); + if (value instanceof Integer) { + int i = (Integer) value; + if ((0 < i) && (i <= 6)) { + return i; + } + } + else if (value instanceof String) { + String s = (String) value; + if (s.equalsIgnoreCase("ABOVE_TOP")) { + return ABOVE_TOP; + } + if (s.equalsIgnoreCase("TOP")) { + return TOP; + } + if (s.equalsIgnoreCase("BELOW_TOP")) { + return BELOW_TOP; + } + if (s.equalsIgnoreCase("ABOVE_BOTTOM")) { + return ABOVE_BOTTOM; + } + if (s.equalsIgnoreCase("BOTTOM")) { + return BOTTOM; + } + if (s.equalsIgnoreCase("BELOW_BOTTOM")) { + return BELOW_BOTTOM; + } + } + return TOP; + } + + private int getJustification(Component c) { + int justification = getTitleJustification(); + if ((justification == LEADING) || (justification == DEFAULT_JUSTIFICATION)) { + return c.getComponentOrientation().isLeftToRight() ? LEFT : RIGHT; + } + if (justification == TRAILING) { + return c.getComponentOrientation().isLeftToRight() ? RIGHT : LEFT; + } + return justification; + } + protected Font getFont(Component c) { - Font font; - if ((font = getTitleFont()) != null) { + Font font = getTitleFont(); + if (font != null) { + return font; + } + font = UIManager.getFont("TitledBorder.font"); + if (font != null) { return font; - } else if (c != null && (font = c.getFont()) != null) { - return font; + } + if (c != null) { + font = c.getFont(); + if (font != null) { + return font; + } } return new Font(Font.DIALOG, Font.PLAIN, 12); } - private static boolean computeIntersection(Rectangle dest, - int rx, int ry, int rw, int rh) { - int x1 = Math.max(rx, dest.x); - int x2 = Math.min(rx + rw, dest.x + dest.width); - int y1 = Math.max(ry, dest.y); - int y2 = Math.min(ry + rh, dest.y + dest.height); - dest.x = x1; - dest.y = y1; - dest.width = x2 - x1; - dest.height = y2 - y1; + private Color getColor(Component c) { + Color color = getTitleColor(); + if (color != null) { + return color; + } + color = UIManager.getColor("TitledBorder.titleColor"); + if (color != null) { + return color; + } + return (c != null) + ? c.getForeground() + : null; + } - if (dest.width <= 0 || dest.height <= 0) { - return false; - } - return true; + private JLabel getLabel(Component c) { + this.label.setText(getTitle()); + this.label.setFont(getFont(c)); + this.label.setForeground(getColor(c)); + this.label.setComponentOrientation(c.getComponentOrientation()); + this.label.setEnabled(c.isEnabled()); + return this.label; } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java Wed Jul 05 17:18:12 2017 +0200 @@ -195,9 +195,8 @@ } ButtonModel model = b.getModel(); + model.setPressed(false); model.setArmed(false); - model.setPressed(false); - b.repaint(); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/swing/plaf/basic/BasicTableHeaderUI.java --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicTableHeaderUI.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicTableHeaderUI.java Wed Jul 05 17:18:12 2017 +0200 @@ -876,7 +876,7 @@ String name = getName(); if (TOGGLE_SORT_ORDER == name) { JTable table = th.getTable(); - RowSorter sorter = table.getRowSorter(); + RowSorter sorter = table == null ? null : table.getRowSorter(); if (sorter != null) { int columnIndex = ui.getSelectedColumnIndex(); columnIndex = table.convertColumnIndexToModel( diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/javax/swing/plaf/nimbus/skin.laf --- a/jdk/src/share/classes/javax/swing/plaf/nimbus/skin.laf Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/javax/swing/plaf/nimbus/skin.laf Wed Jul 05 17:18:12 2017 +0200 @@ -21276,6 +21276,7 @@ + diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/awt/PlatformFont.java --- a/jdk/src/share/classes/sun/awt/PlatformFont.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/awt/PlatformFont.java Wed Jul 05 17:18:12 2017 +0200 @@ -25,10 +25,10 @@ package sun.awt; -import java.awt.GraphicsEnvironment; import java.awt.peer.FontPeer; import java.util.Locale; import java.util.Vector; +import sun.font.SunFontManager; import sun.java2d.FontSupport; import java.nio.CharBuffer; import java.nio.ByteBuffer; @@ -57,9 +57,9 @@ protected static String osVersion; public PlatformFont(String name, int style){ - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - if (ge instanceof FontSupport) { - fontConfig = ((FontSupport)ge).getFontConfiguration(); + SunFontManager sfm = SunFontManager.getInstance(); + if (sfm instanceof FontSupport) { + fontConfig = ((FontSupport)sfm).getFontConfiguration(); } if (fontConfig == null) { return; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/awt/SunToolkit.java --- a/jdk/src/share/classes/sun/awt/SunToolkit.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/awt/SunToolkit.java Wed Jul 05 17:18:12 2017 +0200 @@ -39,6 +39,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import sun.util.logging.PlatformLogger; import sun.misc.SoftCache; @@ -592,7 +593,7 @@ } PostEventQueue postEventQueue = (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); - if(postEventQueue != null) { + if (postEventQueue != null) { postEventQueue.postEvent(event); } } @@ -610,16 +611,29 @@ postEvent(targetToAppContext(e.getSource()), pe); } + private static final Lock flushLock = new ReentrantLock(); + private static boolean isFlushingPendingEvents = false; + /* * Flush any pending events which haven't been posted to the AWT * EventQueue yet. */ public static void flushPendingEvents() { - AppContext appContext = AppContext.getAppContext(); - PostEventQueue postEventQueue = - (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); - if(postEventQueue != null) { - postEventQueue.flush(); + flushLock.lock(); + try { + // Don't call flushPendingEvents() recursively + if (!isFlushingPendingEvents) { + isFlushingPendingEvents = true; + AppContext appContext = AppContext.getAppContext(); + PostEventQueue postEventQueue = + (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); + if (postEventQueue != null) { + postEventQueue.flush(); + } + } + } finally { + isFlushingPendingEvents = false; + flushLock.unlock(); } } @@ -1930,6 +1944,25 @@ return (Window)comp; } + /** + * Returns the value of the system property indicated by the specified key. + */ + public static String getSystemProperty(final String key) { + return (String)AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty(key); + } + }); + } + + /** + * Returns the boolean value of the system property indicated by the specified key. + */ + protected static Boolean getBooleanSystemProperty(String key) { + return Boolean.valueOf(AccessController. + doPrivileged(new GetBooleanAction(key))); + } + private static Boolean sunAwtDisableMixing = null; /** @@ -1938,9 +1971,7 @@ */ public synchronized static boolean getSunAwtDisableMixing() { if (sunAwtDisableMixing == null) { - sunAwtDisableMixing = Boolean.valueOf( - AccessController.doPrivileged( - new GetBooleanAction("sun.awt.disableMixing"))); + sunAwtDisableMixing = getBooleanSystemProperty("sun.awt.disableMixing"); } return sunAwtDisableMixing.booleanValue(); } @@ -2079,12 +2110,14 @@ eventQueue = eq; } - public boolean noEvents() { + public synchronized boolean noEvents() { return queueHead == null; } /* - * Continually post pending AWTEvents to the Java EventQueue. + * Continually post pending AWTEvents to the Java EventQueue. The method + * is synchronized to ensure the flush is completed before a new event + * can be posted to this queue. */ public synchronized void flush() { EventQueueItem tempQueue = queueHead; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/font/FontUtilities.java --- a/jdk/src/share/classes/sun/font/FontUtilities.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/font/FontUtilities.java Wed Jul 05 17:18:12 2017 +0200 @@ -60,6 +60,10 @@ static final String LUCIDA_FILE_NAME = "LucidaSansRegular.ttf"; + private static boolean debugFonts = false; + private static PlatformLogger logger = null; + private static boolean logging; + // This static initializer block figures out the OS constants. static { @@ -115,6 +119,25 @@ File lucidaFile = new File(jreFontDirName + File.separator + LUCIDA_FILE_NAME); isOpenJDK = !lucidaFile.exists(); + + String debugLevel = + System.getProperty("sun.java2d.debugfonts"); + + if (debugLevel != null && !debugLevel.equals("false")) { + debugFonts = true; + logger = PlatformLogger.getLogger("sun.java2d"); + if (debugLevel.equals("warning")) { + logger.setLevel(PlatformLogger.WARNING); + } else if (debugLevel.equals("severe")) { + logger.setLevel(PlatformLogger.SEVERE); + } + } + + if (debugFonts) { + logger = PlatformLogger.getLogger("sun.java2d"); + logging = logger.isEnabled(); + } + return null; } }); @@ -140,32 +163,6 @@ */ public static final int MAX_LAYOUT_CHARCODE = 0x206F; - private static boolean debugFonts = false; - private static PlatformLogger logger = null; - private static boolean logging; - - static { - - String debugLevel = - System.getProperty("sun.java2d.debugfonts"); - - if (debugLevel != null && !debugLevel.equals("false")) { - debugFonts = true; - logger = PlatformLogger.getLogger("sun.java2d"); - if (debugLevel.equals("warning")) { - logger.setLevel(PlatformLogger.WARNING); - } else if (debugLevel.equals("severe")) { - logger.setLevel(PlatformLogger.SEVERE); - } - } - - if (debugFonts) { - logger = PlatformLogger.getLogger("sun.java2d"); - logging = logger.isEnabled(); - } - - } - /** * Calls the private getFont2D() method in java.awt.Font objects. * diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/io/CharToByteDBCS_ASCII.java --- a/jdk/src/share/classes/sun/io/CharToByteDBCS_ASCII.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/io/CharToByteDBCS_ASCII.java Wed Jul 05 17:18:12 2017 +0200 @@ -24,7 +24,6 @@ */ package sun.io; -import sun.nio.cs.Surrogate; import sun.nio.cs.ext.DoubleByte; import static sun.nio.cs.CharsetMapping.*; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/io/CharToByteDBCS_EBCDIC.java --- a/jdk/src/share/classes/sun/io/CharToByteDBCS_EBCDIC.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/io/CharToByteDBCS_EBCDIC.java Wed Jul 05 17:18:12 2017 +0200 @@ -24,7 +24,6 @@ */ package sun.io; -import sun.nio.cs.Surrogate; import sun.nio.cs.ext.DoubleByte; import static sun.nio.cs.CharsetMapping.*; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/java2d/HeadlessGraphicsEnvironment.java --- a/jdk/src/share/classes/sun/java2d/HeadlessGraphicsEnvironment.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/java2d/HeadlessGraphicsEnvironment.java Wed Jul 05 17:18:12 2017 +0200 @@ -59,17 +59,12 @@ * Headless decorator implementation of a SunGraphicsEnvironment */ -public class HeadlessGraphicsEnvironment extends GraphicsEnvironment - implements FontSupport { +public class HeadlessGraphicsEnvironment extends GraphicsEnvironment { private GraphicsEnvironment ge; - private FontSupport fontSupport; public HeadlessGraphicsEnvironment(GraphicsEnvironment ge) { this.ge = ge; - if (ge instanceof FontSupport) { - fontSupport = (FontSupport)ge; - } } public GraphicsDevice[] getScreenDevices() @@ -101,13 +96,6 @@ public String[] getAvailableFontFamilyNames(Locale l) { return ge.getAvailableFontFamilyNames(l); } - public FontConfiguration getFontConfiguration() { - if (fontSupport != null) { - return fontSupport.getFontConfiguration(); - } - return null; - } - /* Used by FontManager : internal API */ public GraphicsEnvironment getSunGraphicsEnvironment() { return ge; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/launcher/LauncherHelper.java --- a/jdk/src/share/classes/sun/launcher/LauncherHelper.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/launcher/LauncherHelper.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,7 +208,7 @@ Method method = null; try { method = clazz.getMethod("main", String[].class); - } catch (Exception e) { + } catch (NoSuchMethodException nsme) { ostream.println(getLocalizedMessage("java.launcher.cls.error4", classname)); throw new RuntimeException("Main method not found in " + classname); @@ -225,8 +225,7 @@ throw new RuntimeException("Main method is not static in class " + classname); } - Class rType = method.getReturnType(); - if (!rType.isPrimitive() || !rType.getName().equals("void")) { + if (method.getReturnType() != java.lang.Void.TYPE) { ostream.println(getLocalizedMessage("java.launcher.cls.error3", classname)); throw new RuntimeException("Main method must return a value" + diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java --- a/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java Wed Jul 05 17:18:12 2017 +0200 @@ -52,14 +52,16 @@ boolean http10 = false; /* for formatting the Date: header */ - static TimeZone tz; - static DateFormat df; - static { - String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz"; - tz = TimeZone.getTimeZone ("GMT"); - df = new SimpleDateFormat (pattern, Locale.US); - df.setTimeZone (tz); - } + private static final String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz"; + private static final TimeZone gmtTZ = TimeZone.getTimeZone("GMT"); + private static final ThreadLocal dateFormat = + new ThreadLocal() { + @Override protected DateFormat initialValue() { + DateFormat df = new SimpleDateFormat(pattern, Locale.US); + df.setTimeZone(gmtTZ); + return df; + } + }; private static final String HEAD = "HEAD"; @@ -206,7 +208,7 @@ PlaceholderOutputStream o = getPlaceholderResponseBody(); tmpout.write (bytes(statusLine, 0), 0, statusLine.length()); boolean noContentToSend = false; // assume there is content - rspHdrs.set ("Date", df.format (new Date())); + rspHdrs.set ("Date", dateFormat.get().format (new Date())); /* check for response type that is not allowed to send a body */ diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java --- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Wed Jul 05 17:18:12 2017 +0200 @@ -2331,7 +2331,7 @@ * closed the connection to the web server. */ private void disconnectWeb() throws IOException { - if (usingProxy()) { + if (usingProxy() && http.isKeepingAlive()) { responseCode = -1; // clean up, particularly, skip the content part // of a 401 error response diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/nio/cs/Surrogate.java --- a/jdk/src/share/classes/sun/nio/cs/Surrogate.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/cs/Surrogate.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,9 @@ * Utility class for dealing with surrogates. * * @author Mark Reinhold + * @author Martin Buchholz + * @author Ulf Zibis */ - public class Surrogate { private Surrogate() { } @@ -75,16 +76,9 @@ } /** - * Tells whether or not the given UCS-4 character is in the Basic - * Multilingual Plane, and can be represented using a single char. - */ - public static boolean isBMPCodePoint(int uc) { - return uc >> 16 == 0; - } - - /** * Tells whether or not the given UCS-4 character must be represented as a * surrogate pair in UTF-16. + * Use of {@link Character#isSupplementaryCodePoint} is generally preferred. */ public static boolean neededFor(int uc) { return Character.isSupplementaryCodePoint(uc); @@ -92,24 +86,25 @@ /** * Returns the high UTF-16 surrogate for the given supplementary UCS-4 character. + * Use of {@link Character#highSurrogate} is generally preferred. */ public static char high(int uc) { assert Character.isSupplementaryCodePoint(uc); - return (char)((uc >> 10) - + (Character.MIN_HIGH_SURROGATE - - (Character.MIN_SUPPLEMENTARY_CODE_POINT >> 10))); + return Character.highSurrogate(uc); } /** * Returns the low UTF-16 surrogate for the given supplementary UCS-4 character. + * Use of {@link Character#lowSurrogate} is generally preferred. */ public static char low(int uc) { assert Character.isSupplementaryCodePoint(uc); - return (char)((uc & 0x3ff) + Character.MIN_LOW_SURROGATE); + return Character.lowSurrogate(uc); } /** * Converts the given surrogate pair into a 32-bit UCS-4 character. + * Use of {@link Character#toCodePoint} is generally preferred. */ public static int toUCS4(char c, char d) { assert Character.isHighSurrogate(c) && Character.isLowSurrogate(d); @@ -290,8 +285,9 @@ * error() will return a descriptive result object */ public int generate(int uc, int len, CharBuffer dst) { - if (Surrogate.isBMPCodePoint(uc)) { - if (Surrogate.is(uc)) { + if (Character.isBmpCodePoint(uc)) { + char c = (char) uc; + if (Character.isSurrogate(c)) { error = CoderResult.malformedForLength(len); return -1; } @@ -299,16 +295,16 @@ error = CoderResult.OVERFLOW; return -1; } - dst.put((char)uc); + dst.put(c); error = null; return 1; - } else if (Character.isSupplementaryCodePoint(uc)) { + } else if (Character.isValidCodePoint(uc)) { if (dst.remaining() < 2) { error = CoderResult.OVERFLOW; return -1; } - dst.put(Surrogate.high(uc)); - dst.put(Surrogate.low(uc)); + dst.put(Character.highSurrogate(uc)); + dst.put(Character.lowSurrogate(uc)); error = null; return 2; } else { @@ -334,8 +330,9 @@ * error() will return a descriptive result object */ public int generate(int uc, int len, char[] da, int dp, int dl) { - if (Surrogate.isBMPCodePoint(uc)) { - if (Surrogate.is(uc)) { + if (Character.isBmpCodePoint(uc)) { + char c = (char) uc; + if (Character.isSurrogate(c)) { error = CoderResult.malformedForLength(len); return -1; } @@ -343,16 +340,16 @@ error = CoderResult.OVERFLOW; return -1; } - da[dp] = (char)uc; + da[dp] = c; error = null; return 1; - } else if (Character.isSupplementaryCodePoint(uc)) { + } else if (Character.isValidCodePoint(uc)) { if (dl - dp < 2) { error = CoderResult.OVERFLOW; return -1; } - da[dp] = Surrogate.high(uc); - da[dp + 1] = Surrogate.low(uc); + da[dp] = Character.highSurrogate(uc); + da[dp + 1] = Character.lowSurrogate(uc); error = null; return 2; } else { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/nio/cs/UTF_32Coder.java --- a/jdk/src/share/classes/sun/nio/cs/UTF_32Coder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/cs/UTF_32Coder.java Wed Jul 05 17:18:12 2017 +0200 @@ -86,22 +86,21 @@ src.position(mark); } } - while (src.remaining() > 3) { + while (src.remaining() >= 4) { cp = getCP(src); - if (cp < 0 || cp > Surrogate.UCS4_MAX) { - return CoderResult.malformedForLength(4); - } - if (cp < Surrogate.UCS4_MIN) { + if (Character.isBmpCodePoint(cp)) { if (!dst.hasRemaining()) return CoderResult.OVERFLOW; mark += 4; - dst.put((char)cp); - } else { + dst.put((char) cp); + } else if (Character.isValidCodePoint(cp)) { if (dst.remaining() < 2) return CoderResult.OVERFLOW; mark += 4; - dst.put(Surrogate.high(cp)); - dst.put(Surrogate.low(cp)); + dst.put(Character.highSurrogate(cp)); + dst.put(Character.lowSurrogate(cp)); + } else { + return CoderResult.malformedForLength(4); } } return CoderResult.UNDERFLOW; @@ -154,7 +153,12 @@ try { while (src.hasRemaining()) { char c = src.get(); - if (Character.isHighSurrogate(c)) { + if (!Character.isSurrogate(c)) { + if (dst.remaining() < 4) + return CoderResult.OVERFLOW; + mark++; + put(c, dst); + } else if (Character.isHighSurrogate(c)) { if (!src.hasRemaining()) return CoderResult.UNDERFLOW; char low = src.get(); @@ -162,17 +166,13 @@ if (dst.remaining() < 4) return CoderResult.OVERFLOW; mark += 2; - put(Surrogate.toUCS4(c, low), dst); + put(Character.toCodePoint(c, low), dst); } else { return CoderResult.malformedForLength(1); } - } else if (Character.isLowSurrogate(c)) { + } else { + // assert Character.isLowSurrogate(c); return CoderResult.malformedForLength(1); - } else { - if (dst.remaining() < 4) - return CoderResult.OVERFLOW; - mark++; - put(c, dst); } } return CoderResult.UNDERFLOW; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/nio/cs/UTF_8.java --- a/jdk/src/share/classes/sun/nio/cs/UTF_8.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/cs/UTF_8.java Wed Jul 05 17:18:12 2017 +0200 @@ -102,7 +102,7 @@ // [F1..F3] [80..BF] [80..BF] [80..BF] // [F4] [80..8F] [80..BF] [80..BF] // only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...] - // will be checked by Surrogate.neededFor(uc) + // will be checked by Character.isSupplementaryCodePoint(uc) private static boolean isMalformed4(int b2, int b3, int b4) { return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 || (b4 & 0xc0) != 0x80; @@ -207,15 +207,15 @@ // ASCII only loop while (dp < dlASCII && sa[sp] >= 0) - da[dp++] = (char)sa[sp++]; + da[dp++] = (char) sa[sp++]; while (sp < sl) { int b1 = sa[sp]; - if (b1 >= 0) { + if (b1 >= 0) { // 1 byte, 7 bits: 0xxxxxxx if (dp >= dl) return xflow(src, sp, sl, dst, dp, 1); - da[dp++] = (char)b1; + da[dp++] = (char) b1; sp++; } else if ((b1 >> 5) == -2) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx @@ -224,7 +224,10 @@ int b2 = sa[sp + 1]; if (isMalformed2(b1, b2)) return malformed(src, sp, dst, dp, 2); - da[dp++] = (char) (((b1 << 6) ^ b2) ^ 0x0f80); + da[dp++] = (char) (((b1 << 6) ^ b2) + ^ + (((byte) 0xC0 << 6) ^ + ((byte) 0x80 << 0))); sp += 2; } else if ((b1 >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx @@ -234,7 +237,13 @@ int b3 = sa[sp + 2]; if (isMalformed3(b1, b2, b3)) return malformed(src, sp, dst, dp, 3); - da[dp++] = (char) (((b1 << 12) ^ (b2 << 6) ^ b3) ^ 0x1f80); + da[dp++] = (char) + ((b1 << 12) ^ + (b2 << 6) ^ + (b3 ^ + (((byte) 0xE0 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0)))); sp += 3; } else if ((b1 >> 3) == -2) { // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx @@ -243,16 +252,21 @@ int b2 = sa[sp + 1]; int b3 = sa[sp + 2]; int b4 = sa[sp + 3]; - int uc = ((b1 & 0x07) << 18) | - ((b2 & 0x3f) << 12) | - ((b3 & 0x3f) << 06) | - (b4 & 0x3f); + int uc = ((b1 << 18) ^ + (b2 << 12) ^ + (b3 << 6) ^ + (b4 ^ + (((byte) 0xF0 << 18) ^ + ((byte) 0x80 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0)))); if (isMalformed4(b2, b3, b4) || - !Surrogate.neededFor(uc)) { + // shortest form check + !Character.isSupplementaryCodePoint(uc)) { return malformed(src, sp, dst, dp, 4); } - da[dp++] = Surrogate.high(uc); - da[dp++] = Surrogate.low(uc); + da[dp++] = Character.highSurrogate(uc); + da[dp++] = Character.lowSurrogate(uc); sp += 4; } else return malformed(src, sp, dst, dp, 1); @@ -270,8 +284,8 @@ if (b1 >= 0) { // 1 byte, 7 bits: 0xxxxxxx if (dst.remaining() < 1) - return xflow(src, mark, 1); //overflow - dst.put((char)b1); + return xflow(src, mark, 1); // overflow + dst.put((char) b1); mark++; } else if ((b1 >> 5) == -2) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx @@ -280,7 +294,10 @@ int b2 = src.get(); if (isMalformed2(b1, b2)) return malformed(src, mark, 2); - dst.put((char) (((b1 << 6) ^ b2) ^ 0x0f80)); + dst.put((char) (((b1 << 6) ^ b2) + ^ + (((byte) 0xC0 << 6) ^ + ((byte) 0x80 << 0)))); mark += 2; } else if ((b1 >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx @@ -290,7 +307,13 @@ int b3 = src.get(); if (isMalformed3(b1, b2, b3)) return malformed(src, mark, 3); - dst.put((char) (((b1 << 12) ^ (b2 << 6) ^ b3) ^ 0x1f80)); + dst.put((char) + ((b1 << 12) ^ + (b2 << 6) ^ + (b3 ^ + (((byte) 0xE0 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0))))); mark += 3; } else if ((b1 >> 3) == -2) { // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx @@ -299,16 +322,21 @@ int b2 = src.get(); int b3 = src.get(); int b4 = src.get(); - int uc = ((b1 & 0x07) << 18) | - ((b2 & 0x3f) << 12) | - ((b3 & 0x3f) << 06) | - (b4 & 0x3f); + int uc = ((b1 << 18) ^ + (b2 << 12) ^ + (b3 << 6) ^ + (b4 ^ + (((byte) 0xF0 << 18) ^ + ((byte) 0x80 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0)))); if (isMalformed4(b2, b3, b4) || - !Surrogate.neededFor(uc)) { // shortest form check + // shortest form check + !Character.isSupplementaryCodePoint(uc)) { return malformed(src, mark, 4); } - dst.put(Surrogate.high(uc)); - dst.put(Surrogate.low(uc)); + dst.put(Character.highSurrogate(uc)); + dst.put(Character.lowSurrogate(uc)); mark += 4; } else { return malformed(src, mark, 1); @@ -366,7 +394,7 @@ int dl = dst.arrayOffset() + dst.limit(); int dlASCII = dp + Math.min(sl - sp, dl - dp); - //ASCII only loop + // ASCII only loop while (dp < dlASCII && sa[sp] < '\u0080') da[dp++] = (byte) sa[sp++]; while (sp < sl) { @@ -380,7 +408,7 @@ // 2 bytes, 11 bits if (dl - dp < 2) return overflow(src, sp, dst, dp); - da[dp++] = (byte)(0xc0 | ((c >> 06))); + da[dp++] = (byte)(0xc0 | (c >> 6)); da[dp++] = (byte)(0x80 | (c & 0x3f)); } else if (Character.isSurrogate(c)) { // Have a surrogate pair @@ -395,7 +423,7 @@ return overflow(src, sp, dst, dp); da[dp++] = (byte)(0xf0 | ((uc >> 18))); da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); - da[dp++] = (byte)(0x80 | ((uc >> 06) & 0x3f)); + da[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f)); da[dp++] = (byte)(0x80 | (uc & 0x3f)); sp++; // 2 chars } else { @@ -403,7 +431,7 @@ if (dl - dp < 3) return overflow(src, sp, dst, dp); da[dp++] = (byte)(0xe0 | ((c >> 12))); - da[dp++] = (byte)(0x80 | ((c >> 06) & 0x3f)); + da[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f)); da[dp++] = (byte)(0x80 | (c & 0x3f)); } sp++; @@ -427,7 +455,7 @@ // 2 bytes, 11 bits if (dst.remaining() < 2) return overflow(src, mark); - dst.put((byte)(0xc0 | ((c >> 06)))); + dst.put((byte)(0xc0 | (c >> 6))); dst.put((byte)(0x80 | (c & 0x3f))); } else if (Character.isSurrogate(c)) { // Have a surrogate pair @@ -442,15 +470,15 @@ return overflow(src, mark); dst.put((byte)(0xf0 | ((uc >> 18)))); dst.put((byte)(0x80 | ((uc >> 12) & 0x3f))); - dst.put((byte)(0x80 | ((uc >> 06) & 0x3f))); + dst.put((byte)(0x80 | ((uc >> 6) & 0x3f))); dst.put((byte)(0x80 | (uc & 0x3f))); - mark++; //2 chars + mark++; // 2 chars } else { // 3 bytes, 16 bits if (dst.remaining() < 3) return overflow(src, mark); dst.put((byte)(0xe0 | ((c >> 12)))); - dst.put((byte)(0x80 | ((c >> 06) & 0x3f))); + dst.put((byte)(0x80 | ((c >> 6) & 0x3f))); dst.put((byte)(0x80 | (c & 0x3f))); } mark++; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/nio/cs/UnicodeEncoder.java --- a/jdk/src/share/classes/sun/nio/cs/UnicodeEncoder.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/cs/UnicodeEncoder.java Wed Jul 05 17:18:12 2017 +0200 @@ -93,8 +93,8 @@ if (dst.remaining() < 4) return CoderResult.OVERFLOW; mark += 2; - put(Surrogate.high(d), dst); - put(Surrogate.low(d), dst); + put(Character.highSurrogate(d), dst); + put(Character.lowSurrogate(d), dst); } return CoderResult.UNDERFLOW; } finally { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/nio/cs/ext/EUC_TW.java --- a/jdk/src/share/classes/sun/nio/cs/ext/EUC_TW.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/cs/ext/EUC_TW.java Wed Jul 05 17:18:12 2017 +0200 @@ -34,7 +34,6 @@ import java.nio.charset.CoderResult; import java.util.Arrays; import sun.nio.cs.HistoricallyNamedCharset; -import sun.nio.cs.Surrogate; import static sun.nio.cs.CharsetMapping.*; public class EUC_TW extends Charset implements HistoricallyNamedCharset @@ -159,8 +158,8 @@ c1[0] = c; return c1; } else { - c2[0] = Surrogate.high(0x20000 + c); - c2[1] = Surrogate.low(0x20000 + c); + c2[0] = Character.highSurrogate(0x20000 + c); + c2[1] = Character.lowSurrogate(0x20000 + c); return c2; } } @@ -441,7 +440,7 @@ } static int encode(char hi, char low, byte[] bb) { - int c = Surrogate.toUCS4(hi, low); + int c = Character.toCodePoint(hi, low); if ((c & 0xf0000) != 0x20000) return -1; c -= 0x20000; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/nio/cs/ext/GB18030.java --- a/jdk/src/share/classes/sun/nio/cs/ext/GB18030.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/cs/ext/GB18030.java Wed Jul 05 17:18:12 2017 +0200 @@ -12628,7 +12628,7 @@ if (Character.isSurrogate(c)) { if ((condensedKey=sgp.parse(c, sa, sp, sl)) < 0) return sgp.error(); - // Surogate.toUCS4 looks like + // Character.toCodePoint looks like // (((high & 0x3ff) << 10) | (low & 0x3ff)) + 0x10000; // so we add (0x2e248 - 0x10000) to get the "key". condensedKey += 0x1E248; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/nio/cs/ext/IBM33722.java --- a/jdk/src/share/classes/sun/nio/cs/ext/IBM33722.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/cs/ext/IBM33722.java Wed Jul 05 17:18:12 2017 +0200 @@ -36,7 +36,6 @@ import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import sun.nio.cs.HistoricallyNamedCharset; -import sun.nio.cs.Surrogate; public class IBM33722 extends Charset diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/nio/cs/ext/IBM964.java --- a/jdk/src/share/classes/sun/nio/cs/ext/IBM964.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/cs/ext/IBM964.java Wed Jul 05 17:18:12 2017 +0200 @@ -36,7 +36,6 @@ import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import sun.nio.cs.HistoricallyNamedCharset; -import sun.nio.cs.Surrogate; public class IBM964 extends Charset diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/Credentials.java --- a/jdk/src/share/classes/sun/security/krb5/Credentials.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/Credentials.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,7 @@ import sun.security.krb5.internal.*; import sun.security.krb5.internal.ccache.CredentialsCache; -import sun.security.krb5.internal.ktab.*; import sun.security.krb5.internal.crypto.EType; -import java.io.File; import java.io.IOException; import java.util.Date; import java.net.InetAddress; @@ -506,59 +504,6 @@ return result; } - - /** - * Gets service credential from key table. The credential is used to - * decrypt the received client message - * and authenticate the client by verifying the client's credential. - * - * @param serviceName the name of service, using format component@realm - * @param keyTabFile the file of key table. - * @return a KrbCreds object. - */ - public static Credentials getServiceCreds(String serviceName, - File keyTabFile) { - EncryptionKey k = null; - PrincipalName service = null; - Credentials result = null; - try { - service = new PrincipalName(serviceName); - if (service.getRealm() == null) { - String realm = Config.getInstance().getDefaultRealm(); - if (realm == null) { - return null; - } else { - service.setRealm(realm); - } - } - } catch (RealmException e) { - if (DEBUG) { - e.printStackTrace(); - } - return null; - } catch (KrbException e) { - if (DEBUG) { - e.printStackTrace(); - } - return null; - } - KeyTab kt; - if (keyTabFile == null) { - kt = KeyTab.getInstance(); - } else { - kt = KeyTab.getInstance(keyTabFile); - } - if ((kt != null) && (kt.findServiceEntry(service))) { - k = kt.readServiceKey(service); - result = new Credentials(null, service, null, null, null, - null, null, null, null, null); - result.serviceKey = k; - } - return result; - } - - - /** * Acquires credentials for a specified service using initial credential. * When the service has a different realm diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/EncryptedData.java --- a/jdk/src/share/classes/sun/security/krb5/EncryptedData.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/EncryptedData.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -336,38 +336,29 @@ } /** - * Reset data stream after decryption, remove redundant bytes. + * Reset asn.1 data stream after decryption, remove redundant bytes. * @param data the decrypted data from decrypt(). - * @param encoded true if the encrypted data is ASN1 encoded data, - * false if the encrypted data is not ASN1 encoded data. * @return the reset byte array which holds exactly one asn1 datum * including its tag and length. * */ - public byte[] reset(byte[] data, boolean encoded) { + public byte[] reset(byte[] data) { byte[] bytes = null; - // if it is encoded data, we use length field to + // for asn.1 encoded data, we use length field to // determine the data length and remove redundant paddings. - if (encoded) { - if ((data[1] & 0xFF) < 128) { - bytes = new byte[data[1] + 2]; - System.arraycopy(data, 0, bytes, 0, data[1] + 2); - } else - if ((data[1] & 0xFF) > 128) { - int len = data[1] & (byte)0x7F; - int result = 0; - for (int i = 0; i < len; i++) { - result |= (data[i + 2] & 0xFF) << (8 * (len - i - 1)); - } - bytes = new byte[result + len + 2]; - System.arraycopy(data, 0, bytes, 0, result + len + 2); + if ((data[1] & 0xFF) < 128) { + bytes = new byte[data[1] + 2]; + System.arraycopy(data, 0, bytes, 0, data[1] + 2); + } else { + if ((data[1] & 0xFF) > 128) { + int len = data[1] & (byte)0x7F; + int result = 0; + for (int i = 0; i < len; i++) { + result |= (data[i + 2] & 0xFF) << (8 * (len - i - 1)); } - } else { - // if it is not encoded, which happens in GSS tokens, - // we remove padding data according to padding pattern. - bytes = new byte[data.length - data[data.length - 1]]; - System.arraycopy(data, 0, bytes, 0, - data.length - data[data.length - 1]); + bytes = new byte[result + len + 2]; + System.arraycopy(data, 0, bytes, 0, result + len + 2); + } } return bytes; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/KrbApRep.java --- a/jdk/src/share/classes/sun/security/krb5/KrbApRep.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/KrbApRep.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,7 +130,7 @@ byte[] temp = rep.encPart.decrypt(tgs_creds.key, KeyUsage.KU_ENC_AP_REP_PART); - byte[] enc_ap_rep_part = rep.encPart.reset(temp, true); + byte[] enc_ap_rep_part = rep.encPart.reset(temp); encoding = new DerValue(enc_ap_rep_part); encPart = new EncAPRepPart(encoding); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/KrbApReq.java --- a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -279,14 +279,14 @@ byte[] bytes = apReqMessg.ticket.encPart.decrypt(dkey, KeyUsage.KU_TICKET); - byte[] temp = apReqMessg.ticket.encPart.reset(bytes, true); + byte[] temp = apReqMessg.ticket.encPart.reset(bytes); EncTicketPart enc_ticketPart = new EncTicketPart(temp); checkPermittedEType(enc_ticketPart.key.getEType()); byte[] bytes2 = apReqMessg.authenticator.decrypt(enc_ticketPart.key, KeyUsage.KU_AP_REQ_AUTHENTICATOR); - byte[] temp2 = apReqMessg.authenticator.reset(bytes2, true); + byte[] temp2 = apReqMessg.authenticator.reset(bytes2); authenticator = new Authenticator(temp2); ctime = authenticator.ctime; cusec = authenticator.cusec; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/KrbAsRep.java --- a/jdk/src/share/classes/sun/security/krb5/KrbAsRep.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/KrbAsRep.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,7 @@ byte[] enc_as_rep_bytes = rep.encPart.decrypt(dkey, KeyUsage.KU_ENC_AS_REP_PART); - byte[] enc_as_rep_part = rep.encPart.reset(enc_as_rep_bytes, true); + byte[] enc_as_rep_part = rep.encPart.reset(enc_as_rep_bytes); encoding = new DerValue(enc_as_rep_part); EncASRepPart enc_part = new EncASRepPart(encoding); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/KrbCred.java --- a/jdk/src/share/classes/sun/security/krb5/KrbCred.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/KrbCred.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,7 +130,7 @@ byte[] temp = credMessg.encPart.decrypt(key, KeyUsage.KU_ENC_KRB_CRED_PART); - byte[] plainText = credMessg.encPart.reset(temp, true); + byte[] plainText = credMessg.encPart.reset(temp); DerValue encoding = new DerValue(plainText); EncKrbCredPart encPart = new EncKrbCredPart(encoding); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/KrbPriv.java --- a/jdk/src/share/classes/sun/security/krb5/KrbPriv.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/KrbPriv.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ package sun.security.krb5; -import sun.security.krb5.EncryptionKey; import sun.security.krb5.internal.*; import sun.security.krb5.internal.crypto.*; import sun.security.util.*; @@ -159,7 +158,7 @@ byte[] bytes = krb_priv.encPart.decrypt(key, KeyUsage.KU_ENC_KRB_PRIV_PART); - byte[] temp = krb_priv.encPart.reset(bytes, true); + byte[] temp = krb_priv.encPart.reset(bytes); DerValue ref = new DerValue(temp); EncKrbPrivPart enc_part = new EncKrbPrivPart(ref); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/KrbTgsRep.java --- a/jdk/src/share/classes/sun/security/krb5/KrbTgsRep.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/KrbTgsRep.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,7 @@ tgsReq.usedSubkey() ? KeyUsage.KU_ENC_TGS_REP_PART_SUBKEY : KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY); - byte[] enc_tgs_rep_part = rep.encPart.reset(enc_tgs_rep_bytes, true); + byte[] enc_tgs_rep_part = rep.encPart.reset(enc_tgs_rep_bytes); ref = new DerValue(enc_tgs_rep_part); EncTGSRepPart enc_part = new EncTGSRepPart(ref); rep.ticket.sname.setRealm(rep.ticket.realm); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/internal/crypto/EType.java --- a/jdk/src/share/classes/sun/security/krb5/internal/crypto/EType.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/internal/crypto/EType.java Wed Jul 05 17:18:12 2017 +0200 @@ -185,20 +185,20 @@ // is set to false. private static final int[] BUILTIN_ETYPES = new int[] { - EncryptedData.ETYPE_DES_CBC_MD5, - EncryptedData.ETYPE_DES_CBC_CRC, + EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96, + EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, + EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD, EncryptedData.ETYPE_ARCFOUR_HMAC, - EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD, - EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, - EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96, + EncryptedData.ETYPE_DES_CBC_CRC, + EncryptedData.ETYPE_DES_CBC_MD5, }; private static final int[] BUILTIN_ETYPES_NOAES256 = new int[] { - EncryptedData.ETYPE_DES_CBC_MD5, - EncryptedData.ETYPE_DES_CBC_CRC, + EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, + EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD, EncryptedData.ETYPE_ARCFOUR_HMAC, - EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD, - EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, + EncryptedData.ETYPE_DES_CBC_CRC, + EncryptedData.ETYPE_DES_CBC_MD5, }; @@ -217,8 +217,8 @@ result = BUILTIN_ETYPES; } if (!ALLOW_WEAK_CRYPTO) { - // The first 2 etypes are now weak ones - return Arrays.copyOfRange(result, 2, result.length); + // The last 2 etypes are now weak ones + return Arrays.copyOfRange(result, 0, result.length - 2); } return result; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java --- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -228,37 +228,6 @@ } /** - * Reads the service key from the keytab file. - * @param service the PrincipalName of the requested service. - * @return the last service key in the keytab with the highest kvno - */ - public EncryptionKey readServiceKey(PrincipalName service) { - KeyTabEntry entry = null; - EncryptionKey key = null; - if (entries != null) { - // Find latest entry for this service that has an etype - // that has been configured for use - for (int i = entries.size()-1; i >= 0; i--) { - entry = entries.elementAt(i); - if (entry.service.match(service)) { - if (EType.isSupported(entry.keyType)) { - if (key == null || - entry.keyVersion > key.getKeyVersionNumber()) { - key = new EncryptionKey(entry.keyblock, - entry.keyType, - new Integer(entry.keyVersion)); - } - } else if (DEBUG) { - System.out.println("Found unsupported keytype (" + - entry.keyType + ") for " + service); - } - } - } - } - return key; - } - - /** * Reads all keys for a service from the keytab file that have * etypes that have been configured for use. If there are multiple * keys with same etype, the one with the highest kvno is returned. @@ -309,7 +278,7 @@ Arrays.sort(retVal, new Comparator() { @Override public int compare(EncryptionKey o1, EncryptionKey o2) { - if (etypes != null && etypes != EType.getBuiltInDefaults()) { + if (etypes != null) { int o1EType = o1.getEType(); int o2EType = o2.getEType(); if (o1EType != o2EType) { @@ -320,6 +289,9 @@ return 1; } } + // Neither o1EType nor o2EType in default_tkt_enctypes, + // therefore won't be used in AS-REQ. We do not care + // about their order, use kvno is OK. } } return o2.getKeyVersionNumber().intValue() diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java --- a/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,24 +180,15 @@ String alias; }; - private static class KeyId { - byte[] keyId; - - KeyId(byte[] keyId) { + // A certificate with its PKCS #9 attributes + private static class CertEntry { + final X509Certificate cert; + final byte[] keyId; + final String alias; + CertEntry(X509Certificate cert, byte[] keyId, String alias) { + this.cert = cert; this.keyId = keyId; - } - public int hashCode() { - int hash = 0; - - for (int i = 0; i < keyId.length; i++) - hash += keyId[i]; - return hash; - } - public boolean equals(Object obj) { - if (!(obj instanceof KeyId)) - return false; - KeyId that = (KeyId)obj; - return (Arrays.equals(this.keyId, that.keyId)); + this.alias = alias; } } @@ -209,7 +200,9 @@ new Hashtable(); private ArrayList keyList = new ArrayList(); - private LinkedHashMap certs = new LinkedHashMap(); + private LinkedHashMap certsMap = + new LinkedHashMap(); + private ArrayList certEntries = new ArrayList(); /** * Returns the key associated with the given alias, using the given @@ -472,6 +465,15 @@ KeyEntry entry = new KeyEntry(); entry.date = new Date(); + try { + // set the keyId to current date + entry.keyId = ("Time " + (entry.date).getTime()).getBytes("UTF8"); + } catch (UnsupportedEncodingException ex) { + // Won't happen + } + // set the alias + entry.alias = alias.toLowerCase(); + entry.protectedPrivKey = key.clone(); if (chain != null) { entry.chain = chain.clone(); @@ -1027,10 +1029,9 @@ // All Certs should have a unique friendlyName. // This change is made to meet NSS requirements. byte[] bagAttrs = null; - String friendlyName = cert.getSubjectX500Principal().getName(); if (i == 0) { // Only End-Entity Cert should have a localKeyId. - bagAttrs = getBagAttributes(friendlyName, entry.keyId); + bagAttrs = getBagAttributes(entry.alias, entry.keyId); } else { // Trusted root CA certs and Intermediate CA certs do not // need to have a localKeyId, and hence localKeyId is null @@ -1038,7 +1039,8 @@ // NSS pkcs12 library requires trusted CA certs in the // certificate chain to have unique or null localKeyID. // However, IE/OpenSSL do not impose this restriction. - bagAttrs = getBagAttributes(friendlyName, null); + bagAttrs = getBagAttributes( + cert.getSubjectX500Principal().getName(), null); } if (bagAttrs != null) { safeBag.write(bagAttrs); @@ -1333,24 +1335,49 @@ if (entry.keyId != null) { ArrayList chain = new ArrayList(); - X509Certificate cert = certs.get(new KeyId(entry.keyId)); + X509Certificate cert = findMatchedCertificate(entry); while (cert != null) { chain.add(cert); X500Principal issuerDN = cert.getIssuerX500Principal(); if (issuerDN.equals(cert.getSubjectX500Principal())) { break; } - cert = certs.get(issuerDN); + cert = certsMap.get(issuerDN); } /* Update existing KeyEntry in entries table */ if (chain.size() > 0) entry.chain = chain.toArray(new Certificate[chain.size()]); } } - certs.clear(); + certEntries.clear(); + certsMap.clear(); keyList.clear(); } + /** + * Locates a matched CertEntry from certEntries, and returns its cert. + * @param entry the KeyEntry to match + * @return a certificate, null if not found + */ + private X509Certificate findMatchedCertificate(KeyEntry entry) { + CertEntry keyIdMatch = null; + CertEntry aliasMatch = null; + for (CertEntry ce: certEntries) { + if (Arrays.equals(entry.keyId, ce.keyId)) { + keyIdMatch = ce; + if (entry.alias.equalsIgnoreCase(ce.alias)) { + // Full match! + return ce.cert; + } + } else if (entry.alias.equalsIgnoreCase(ce.alias)) { + aliasMatch = ce; + } + } + // keyId match first, for compatibility + if (keyIdMatch != null) return keyIdMatch.cert; + else if (aliasMatch != null) return aliasMatch.cert; + else return null; + } private void loadSafeContents(DerInputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException @@ -1491,19 +1518,12 @@ keyId = "01".getBytes("UTF8"); } } - if (keyId != null) { - KeyId keyid = new KeyId(keyId); - if (!certs.containsKey(keyid)) - certs.put(keyid, cert); - } - if (alias != null) { - if (!certs.containsKey(alias)) - certs.put(alias, cert); - } + certEntries.add(new CertEntry(cert, keyId, alias)); X500Principal subjectDN = cert.getSubjectX500Principal(); if (subjectDN != null) { - if (!certs.containsKey(subjectDN)) - certs.put(subjectDN, cert); + if (!certsMap.containsKey(subjectDN)) { + certsMap.put(subjectDN, cert); + } } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java --- a/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java Wed Jul 05 17:18:12 2017 +0200 @@ -212,7 +212,7 @@ byte[] bytes = encPart.decrypt(secretKey, KeyUsage.KU_TICKET); // Reset data stream after decryption, remove redundant bytes - byte[] temp = encPart.reset(bytes, true); + byte[] temp = encPart.reset(bytes); EncTicketPart encTicketPart = new EncTicketPart(temp); // Record the Kerberos Principals diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java --- a/jdk/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ import java.io.*; import java.security.*; -import java.security.interfaces.*; +import java.util.Arrays; import javax.net.ssl.*; @@ -128,8 +128,8 @@ "are not supported for TLS Kerberos cipher suites"); } - // Decrypt premaster secret - try { + // Decrypt premaster secret + try { EncryptedData data = new EncryptedData(sessionKey.getEType(), null /* optional kvno */, encrypted); @@ -141,8 +141,25 @@ } } - // Reset data stream after decryption, remove redundant bytes - preMaster = data.reset(temp, false); + // Remove padding bytes after decryption. Only DES and DES3 have + // paddings and we don't support DES3 in TLS (see above) + + if (temp.length == 52 && + data.getEType() == EncryptedData.ETYPE_DES_CBC_CRC) { + // For des-cbc-crc, 4 paddings. Value can be 0x04 or 0x00. + if (paddingByteIs(temp, 52, (byte)4) || + paddingByteIs(temp, 52, (byte)0)) { + temp = Arrays.copyOf(temp, 48); + } + } else if (temp.length == 56 && + data.getEType() == EncryptedData.ETYPE_DES_CBC_MD5) { + // For des-cbc-md5, 8 paddings with 0x08, or no padding + if (paddingByteIs(temp, 56, (byte)8)) { + temp = Arrays.copyOf(temp, 48); + } + } + + preMaster = temp; protocolVersion = ProtocolVersion.valueOf(preMaster[0], preMaster[1]); @@ -191,6 +208,19 @@ } } + /** + * Checks if all paddings of data are b + * @param data the block with padding + * @param len length of data, >= 48 + * @param b expected padding byte + */ + private static boolean paddingByteIs(byte[] data, int len, byte b) { + for (int i=48; isdOps.Lock = BufImg_Lock; bisdo->sdOps.GetRasInfo = BufImg_GetRasInfo; bisdo->sdOps.Release = BufImg_Release; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/solaris/bin/java_md.c --- a/jdk/src/solaris/bin/java_md.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/solaris/bin/java_md.c Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -183,13 +183,9 @@ } void -CreateExecutionEnvironment(int *_argcp, - char ***_argvp, - char jrepath[], - jint so_jrepath, - char jvmpath[], - jint so_jvmpath, - char **original_argv) { +CreateExecutionEnvironment(int *pargc, char ***pargv, + char jrepath[], jint so_jrepath, + char jvmpath[], jint so_jvmpath) { /* * First, determine if we are running the desired data model. If we * are running the desired data model, all the error messages @@ -200,18 +196,17 @@ * os/processor combination has dual mode capabilities. */ - int original_argc = *_argcp; jboolean jvmpathExists; /* Compute/set the name of the executable */ - SetExecname(*_argvp); + SetExecname(*pargv); /* Check data model flags, and exec process, if needed */ { char *arch = (char *)GetArch(); /* like sparc or sparcv9 */ char * jvmtype = NULL; - int argc = *_argcp; - char **argv = original_argv; + int argc = *pargc; + char **argv = *pargv; int running = CURRENT_DATA_MODEL; @@ -233,7 +228,7 @@ { /* open new scope to declare local variables */ int i; - newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(*newargv)); + newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(char*)); newargv[newargc++] = argv[0]; /* scan for data model arguments and remove from argument list; @@ -293,7 +288,11 @@ } jvmpath[0] = '\0'; - jvmtype = CheckJvmType(_argcp, _argvp, JNI_FALSE); + jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE); + if (JLI_StrCmp(jvmtype, "ERROR") == 0) { + JLI_ReportErrorMessage(CFG_ERROR9); + exit(4); + } if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch )) { JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); @@ -309,7 +308,9 @@ if (running != wanted) { /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) { - goto EndDataModelSpeculate; + /* give up and let other code report error message */ + JLI_ReportErrorMessage(JRE_ERROR2, wanted); + exit(1); } /* @@ -317,16 +318,21 @@ * selection options. */ if (ReadKnownVMs(jrepath, GetArchPath(wanted), JNI_TRUE) < 1) { - goto EndDataModelSpeculate; + /* give up and let other code report error message */ + JLI_ReportErrorMessage(JRE_ERROR2, wanted); + exit(1); } jvmpath[0] = '\0'; - jvmtype = CheckJvmType(_argcp, _argvp, JNI_TRUE); + jvmtype = CheckJvmType(pargc, pargv, JNI_TRUE); + if (JLI_StrCmp(jvmtype, "ERROR") == 0) { + JLI_ReportErrorMessage(CFG_ERROR9); + exit(4); + } + /* exec child can do error checking on the existence of the path */ jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted)); } - EndDataModelSpeculate: /* give up and let other code report error message */ - ; #else JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); @@ -398,9 +404,9 @@ struct stat s; if (JLI_StrChr(jvmtype, '/')) { - sprintf(jvmpath, "%s/" JVM_DLL, jvmtype); + JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype); } else { - sprintf(jvmpath, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype); + JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype); } JLI_TraceLauncher("Does `%s' exist ... ", jvmpath); @@ -424,26 +430,24 @@ if (GetApplicationHome(path, pathsize)) { /* Is JRE co-located with the application? */ - sprintf(libjava, "%s/lib/%s/" JAVA_DLL, path, arch); + JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch); if (access(libjava, F_OK) == 0) { - goto found; + JLI_TraceLauncher("JRE path is %s\n", path); + return JNI_TRUE; } /* Does the app ship a private JRE in /jre directory? */ - sprintf(libjava, "%s/jre/lib/%s/" JAVA_DLL, path, arch); + JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/%s/" JAVA_DLL, path, arch); if (access(libjava, F_OK) == 0) { JLI_StrCat(path, "/jre"); - goto found; + JLI_TraceLauncher("JRE path is %s\n", path); + return JNI_TRUE; } } if (!speculative) JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; - - found: - JLI_TraceLauncher("JRE path is %s\n", path); - return JNI_TRUE; } jboolean @@ -463,14 +467,18 @@ int location; fp = fopen(jvmpath, "r"); - if(fp == NULL) - goto error; + if (fp == NULL) { + JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); + return JNI_FALSE; + } /* read in elf header */ count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp); fclose(fp); - if(count < 1) - goto error; + if (count < 1) { + JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); + return JNI_FALSE; + } /* * Check for running a server vm (compiled with -xarch=v8plus) @@ -481,41 +489,42 @@ * does not have to be checked for in binaries with an LP64 data * model. */ - if(elf_head.e_machine == EM_SPARC32PLUS) { + if (elf_head.e_machine == EM_SPARC32PLUS) { char buf[257]; /* recommended buffer size from sysinfo man page */ long length; char* location; length = sysinfo(SI_ISALIST, buf, 257); - if(length > 0) { - location = JLI_StrStr(buf, "sparcv8plus "); - if(location == NULL) { + if (length > 0) { + location = JLI_StrStr(buf, "sparcv8plus "); + if (location == NULL) { JLI_ReportErrorMessage(JVM_ERROR3); return JNI_FALSE; } } } #endif - JLI_ReportErrorMessage(DLL_ERROR1, __LINE__); - goto error; + JLI_ReportErrorMessage(DLL_ERROR1, __LINE__); + JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); + return JNI_FALSE; } ifn->CreateJavaVM = (CreateJavaVM_t) - dlsym(libjvm, "JNI_CreateJavaVM"); - if (ifn->CreateJavaVM == NULL) - goto error; + dlsym(libjvm, "JNI_CreateJavaVM"); + if (ifn->CreateJavaVM == NULL) { + JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); + return JNI_FALSE; + } ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); - if (ifn->GetDefaultJavaVMInitArgs == NULL) - goto error; + if (ifn->GetDefaultJavaVMInitArgs == NULL) { + JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); + return JNI_FALSE; + } return JNI_TRUE; - -error: - JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); - return JNI_FALSE; } /* @@ -575,7 +584,7 @@ char name[PATH_MAX + 2], *real; if ((JLI_StrLen(indir) + JLI_StrLen(cmd) + 1) > PATH_MAX) return 0; - sprintf(name, "%s%c%s", indir, FILE_SEPARATOR, cmd); + JLI_Snprintf(name, sizeof(name), "%s%c%s", indir, FILE_SEPARATOR, cmd); if (!ProgramExists(name)) return 0; real = JLI_MemAlloc(PATH_MAX + 2); if (!realpath(name, real)) @@ -622,7 +631,7 @@ else { /* relative path element */ char dir[2*PATH_MAX]; - sprintf(dir, "%s%c%s", getcwd(cwdbuf, sizeof(cwdbuf)), + JLI_Snprintf(dir, sizeof(dir), "%s%c%s", getcwd(cwdbuf, sizeof(cwdbuf)), FILE_SEPARATOR, s); result = Resolve(dir, program); } @@ -746,7 +755,7 @@ if (JLI_StrLen(path) + JLI_StrLen(dir) + 11 > PATH_MAX) return (0); /* Silently reject "impossibly" long paths */ - sprintf(buffer, "%s/%s/bin/java", path, dir); + JLI_Snprintf(buffer, sizeof(buffer), "%s/%s/bin/java", path, dir); return ((access(buffer, X_OK) == 0) ? 1 : 0); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/solaris/classes/sun/awt/X11/XToolkit.java --- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Wed Jul 05 17:18:12 2017 +0200 @@ -1053,10 +1053,28 @@ return peer; } + private static Boolean sunAwtDisableGtkFileDialogs = null; + + /** + * Returns the value of "sun.awt.disableGtkFileDialogs" property. Default + * value is {@code false}. + */ + public synchronized static boolean getSunAwtDisableGtkFileDialogs() { + if (sunAwtDisableGtkFileDialogs == null) { + sunAwtDisableGtkFileDialogs = + getBooleanSystemProperty("sun.awt.disableGtkFileDialogs"); + } + return sunAwtDisableGtkFileDialogs.booleanValue(); + } + public FileDialogPeer createFileDialog(FileDialog target) { + FileDialogPeer peer = null; // The current GtkFileChooser is available from GTK+ 2.4 - FileDialogPeer peer = checkGtkVersion(2, 4, 0) ? new GtkFileDialogPeer( - target) : new XFileDialogPeer(target); + if (!getSunAwtDisableGtkFileDialogs() && checkGtkVersion(2, 4, 0)) { + peer = new GtkFileDialogPeer(target); + } else { + peer = new XFileDialogPeer(target); + } targetCreatedPeer(target, peer); return peer; } @@ -1201,14 +1219,6 @@ } } - static String getSystemProperty(final String name) { - return (String)AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return System.getProperty(name); - } - }); - } - public PrintJob getPrintJob(final Frame frame, final String doctitle, final Properties props) { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/solaris/classes/sun/awt/X11/XWindow.java --- a/jdk/src/solaris/classes/sun/awt/X11/XWindow.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindow.java Wed Jul 05 17:18:12 2017 +0200 @@ -778,8 +778,8 @@ x, y, xbe.get_x_root(), xbe.get_y_root(), - clickCount,false,MouseWheelEvent.WHEEL_UNIT_SCROLL, - 3,button==4 ? -1 : 1); + 1,false,MouseWheelEvent.WHEEL_UNIT_SCROLL, + 3,button==4 ? -1*clickCount : 1*clickCount); postEventToEventQueue(mwe); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/solaris/demo/jni/Poller/Poller.c --- a/jdk/src/solaris/demo/jni/Poller/Poller.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/solaris/demo/jni/Poller/Poller.c Wed Jul 05 17:18:12 2017 +0200 @@ -160,10 +160,10 @@ return -1; } -#define MEMORY_EXCEPTION(str) throwOutOfMemoryError(env, "Poller:" ## str) -#define STATE_EXCEPTION(str) throwIllegalStateException(env, "Poller:" ## str) +#define MEMORY_EXCEPTION(str) throwOutOfMemoryError(env, "Poller:" str) +#define STATE_EXCEPTION(str) throwIllegalStateException(env, "Poller:" str) #define INTERRUPT_EXCEPTION(str) throwInterruptedIOException(env, \ - "Poller:" ## str) + "Poller:" str) jint addfd(JNIEnv *, ioevent_t *, jint, jshort); jint removefd(JNIEnv *, ioevent_t *, jint); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/solaris/native/java/net/NetworkInterface.c --- a/jdk/src/solaris/native/java/net/NetworkInterface.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/solaris/native/java/net/NetworkInterface.c Wed Jul 05 17:18:12 2017 +0200 @@ -23,6 +23,7 @@ * questions. */ + #include #include #include @@ -33,23 +34,23 @@ #include #include #include + #ifdef __solaris__ #include #include #include +#include #endif + #ifdef __linux__ #include #include #include #include #include -#else -#include #endif #ifdef __linux__ -#define ifr_index ifr_ifindex #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" #endif @@ -108,20 +109,41 @@ static jfieldID ni_ib4broadcastID; static jfieldID ni_ib4maskID; +/** Private methods declarations **/ static jobject createNetworkInterface(JNIEnv *env, netif *ifs); +static int getFlags0(JNIEnv *env, jstring ifname); -static netif *enumInterfaces(JNIEnv *env); -static netif *enumIPv4Interfaces(JNIEnv *env, netif *ifs); +static netif *enumInterfaces(JNIEnv *env); +static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs); + #ifdef AF_INET6 -static netif *enumIPv6Interfaces(JNIEnv *env, netif *ifs); +static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs); #endif -static netif *addif(JNIEnv *env, netif *ifs, char *if_name, int index, - int family, struct sockaddr *new_addrP, int new_addrlen, - short prefix); -static void freeif(netif *ifs); -static struct sockaddr *getBroadcast(JNIEnv *env, const char *ifname); -static short getSubnet(JNIEnv *env, const char *ifname); +static netif *addif(JNIEnv *env, int sock, const char * if_name, netif *ifs, struct sockaddr* ifr_addrP, int family, short prefix); +static void freeif(netif *ifs); + +static int openSocket(JNIEnv *env, int proto); +static int openSocketWithFallback(JNIEnv *env, const char *ifname); + + +static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *name, struct sockaddr *brdcast_store); +static short getSubnet(JNIEnv *env, int sock, const char *ifname); +static int getIndex(int sock, const char *ifname); + +static int getFlags(JNIEnv *env, int sock, const char *ifname); +static int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf); +static int getMTU(JNIEnv *env, int sock, const char *ifname); + + + +#ifdef __solaris__ +static netif *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family); +static int getMacFromDevice(JNIEnv *env, const char* ifname, unsigned char* retbuf); +#endif + + +/******************* Java entry points *****************************/ /* * Class: java_net_NetworkInterface @@ -172,7 +194,7 @@ netif *ifs, *curr; jboolean isCopy; - const char* name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); + const char* name_utf; jobject obj = NULL; ifs = enumInterfaces(env); @@ -180,6 +202,8 @@ return NULL; } + name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); + /* * Search the list of interface based on name */ @@ -253,12 +277,13 @@ (JNIEnv *env, jclass cls, jobject iaObj) { netif *ifs, *curr; + #ifdef AF_INET6 - int family = (*env)->GetIntField(env, iaObj, ni_iafamilyID) == IPv4? - AF_INET : AF_INET6; + int family = ( (*env)->GetIntField(env, iaObj, ni_iafamilyID) == IPv4 ) ? AF_INET : AF_INET6; #else - int family = AF_INET; + int family = AF_INET; #endif + jobject obj = NULL; jboolean match = JNI_FALSE; @@ -390,18 +415,169 @@ return netIFArr; } + +/* + * Class: java_net_NetworkInterface + * Method: isUp0 + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0(JNIEnv *env, jclass cls, jstring name, jint index) { + int ret = getFlags0(env, name); + return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: java_net_NetworkInterface + * Method: isP2P0 + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) { + int ret = getFlags0(env, name); + return (ret & IFF_POINTOPOINT) ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: java_net_NetworkInterface + * Method: isLoopback0 + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0(JNIEnv *env, jclass cls, jstring name, jint index) { + int ret = getFlags0(env, name); + return (ret & IFF_LOOPBACK) ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: java_net_NetworkInterface + * Method: supportsMulticast0 + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0(JNIEnv *env, jclass cls, jstring name, jint index) { + int ret = getFlags0(env, name); + return (ret & IFF_MULTICAST) ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: java_net_NetworkInterface + * Method: getMacAddr0 + * Signature: ([bLjava/lang/String;I)[b + */ +JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0(JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) { + jint addr; + jbyte caddr[4]; + struct in_addr iaddr; + jbyteArray ret = NULL; + unsigned char mac[16]; + int len; + int sock; + jboolean isCopy; + const char* name_utf; + + name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); + + if ((sock =openSocketWithFallback(env, name_utf)) < 0) { + (*env)->ReleaseStringUTFChars(env, name, name_utf); + return JNI_FALSE; + } + + + if (!IS_NULL(addrArray)) { + (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); + addr = ((caddr[0]<<24) & 0xff000000); + addr |= ((caddr[1] <<16) & 0xff0000); + addr |= ((caddr[2] <<8) & 0xff00); + addr |= (caddr[3] & 0xff); + iaddr.s_addr = htonl(addr); + len = getMacAddress(env, sock, name_utf, &iaddr, mac); + } else { + len = getMacAddress(env, sock, name_utf,NULL, mac); + } + if (len > 0) { + ret = (*env)->NewByteArray(env, len); + if (IS_NULL(ret)) { + /* we may have memory to free at the end of this */ + goto fexit; + } + (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) (mac)); + } + fexit: + /* release the UTF string and interface list */ + (*env)->ReleaseStringUTFChars(env, name, name_utf); + + close(sock); + return ret; +} + +/* + * Class: java_net_NetworkInterface + * Method: getMTU0 + * Signature: ([bLjava/lang/String;I)I + */ + +JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) { + jboolean isCopy; + int ret = -1; + int sock; + const char* name_utf; + + name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); + + if ((sock =openSocketWithFallback(env, name_utf)) < 0) { + (*env)->ReleaseStringUTFChars(env, name, name_utf); + return JNI_FALSE; + } + + ret = getMTU(env, sock, name_utf); + + (*env)->ReleaseStringUTFChars(env, name, name_utf); + + close(sock); + return ret; +} + +/*** Private methods definitions ****/ + +static int getFlags0(JNIEnv *env, jstring name) { + jboolean isCopy; + int ret, sock; + const char* name_utf; + + name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); + + if ((sock = openSocketWithFallback(env, name_utf)) < 0) { + (*env)->ReleaseStringUTFChars(env, name, name_utf); + return -1; + } + + name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); + + ret = getFlags(env, sock, name_utf); + + close(sock); + (*env)->ReleaseStringUTFChars(env, name, name_utf); + + if (ret < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFFLAGS failed"); + return -1; + } + + return ret; +} + + + + /* * Create a NetworkInterface object, populate the name and index, and * populate the InetAddress array based on the IP addresses for this * interface. */ -jobject createNetworkInterface(JNIEnv *env, netif *ifs) -{ +jobject createNetworkInterface(JNIEnv *env, netif *ifs) { jobject netifObj; jobject name; jobjectArray addrArr; jobjectArray bindArr; jobjectArray childArr; + netaddr *addrs; jint addr_index, addr_count, bind_index; jint child_count, child_index; netaddr *addrP; @@ -441,7 +617,7 @@ bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL); if (bindArr == NULL) { - return NULL; + return NULL; } addrP = ifs->addr; addr_index = 0; @@ -453,23 +629,22 @@ if (addrP->family == AF_INET) { iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); if (iaObj) { - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr)); + (*env)->SetIntField(env, iaObj, ni_iaaddressID, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr)); } ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); if (ibObj) { - (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj); - if (addrP->brdcast) { - jobject ia2Obj = NULL; - ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); - if (ia2Obj) { - (*env)->SetIntField(env, ia2Obj, ni_iaaddressID, - htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr)); - (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj); - (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask); - } - } - (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj); + (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj); + if (addrP->brdcast) { + jobject ia2Obj = NULL; + ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); + if (ia2Obj) { + (*env)->SetIntField(env, ia2Obj, ni_iaaddressID, + htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr)); + (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj); + (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask); + } + } + (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj); } } @@ -483,14 +658,10 @@ return NULL; } (*env)->SetByteArrayRegion(env, ipaddress, 0, 16, - (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr)); -#ifdef __linux__ - if (!kernelIsV22()) { - scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id; - } -#else + (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr)); + scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id; -#endif + if (scope != 0) { /* zero is default value, no need to set */ (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope); (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE); @@ -500,9 +671,9 @@ } ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); if (ibObj) { - (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj); - (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask); - (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj); + (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj); + (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask); + (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj); } } #endif @@ -521,13 +692,13 @@ child_count = 0; childP = ifs->childs; while (childP) { - child_count++; - childP = childP->next; + child_count++; + childP = childP->next; } childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL); if (childArr == NULL) { - return NULL; + return NULL; } /* @@ -539,7 +710,7 @@ while(childP) { tmp = createNetworkInterface(env, childP); if (tmp == NULL) { - return NULL; + return NULL; } (*env)->SetObjectField(env, tmp, ni_parentID, netifObj); (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp); @@ -558,294 +729,56 @@ */ static netif *enumInterfaces(JNIEnv *env) { netif *ifs; + int sock; /* * Enumerate IPv4 addresses */ - ifs = enumIPv4Interfaces(env, NULL); - if (ifs == NULL) { - if ((*env)->ExceptionOccurred(env)) { - return NULL; - } + + sock = openSocket(env, AF_INET); + if (sock < 0 && (*env)->ExceptionOccurred(env)) { + return NULL; } + ifs = enumIPv4Interfaces(env, sock, NULL); + close(sock); + + if (ifs == NULL && (*env)->ExceptionOccurred(env)) { + return NULL; + } + + /* return partial list if exception occure in the middle of process ???*/ + /* * If IPv6 is available then enumerate IPv6 addresses. */ #ifdef AF_INET6 - if (ipv6_available()) { - ifs = enumIPv6Interfaces(env, ifs); + sock = openSocket(env, AF_INET6); + if (sock < 0 && (*env)->ExceptionOccurred(env)) { + freeif(ifs); + return NULL; + } + + ifs = enumIPv6Interfaces(env, sock, ifs); + close(sock); if ((*env)->ExceptionOccurred(env)) { freeif(ifs); return NULL; } - } #endif return ifs; } - -/* - * Enumerates and returns all IPv4 interfaces - */ -static netif *enumIPv4Interfaces(JNIEnv *env, netif *ifs) { - int sock; - struct ifconf ifc; - struct ifreq *ifreqP; - char *buf; - int numifs; - unsigned i; - unsigned bufsize; - - sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - /* - * If EPROTONOSUPPORT is returned it means we don't have - * IPv4 support so don't throw an exception. - */ - if (errno != EPROTONOSUPPORT) { - NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - } - return ifs; - } - -#ifdef __linux__ - /* need to do a dummy SIOCGIFCONF to determine the buffer size. - * SIOCGIFCOUNT doesn't work - */ - ifc.ifc_buf = NULL; - if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { - NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", - "ioctl SIOCGIFCONF failed"); - close(sock); - return ifs; - } - bufsize = ifc.ifc_len; -#else - if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) { - NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", - "ioctl SIOCGIFNUM failed"); - close(sock); - return ifs; - } - bufsize = numifs * sizeof (struct ifreq); -#endif /* __linux__ */ - - buf = (char *)malloc(bufsize); - if (!buf) { - JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); - (void) close(sock); - return ifs; - } - ifc.ifc_len = bufsize; - ifc.ifc_buf = buf; - if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { - NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", - "ioctl SIOCGIFCONF failed"); - (void) close(sock); - (void) free(buf); - return ifs; - } - - /* - * Iterate through each interface - */ - ifreqP = ifc.ifc_req; - for (i=0; iifr_name); - - /* - * Try to get the interface index - * (Not supported on Solaris 2.6 or 7) - */ - if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) >= 0) { - index = if2.ifr_index; - } else { - index = -1; - } - - /* - * Add to the list - */ - ifs = addif(env, ifs, ifreqP->ifr_name, index, AF_INET, - (struct sockaddr *)&(ifreqP->ifr_addr), - sizeof(struct sockaddr_in), 0); - - /* - * If an exception occurred then free the list - */ - if ((*env)->ExceptionOccurred(env)) { - close(sock); - free(buf); - freeif(ifs); - return NULL; - } - } - - /* - * Free socket and buffer - */ - close(sock); - free(buf); - return ifs; -} - - -#if defined(__solaris__) && defined(AF_INET6) -/* - * Enumerates and returns all IPv6 interfaces on Solaris - */ -static netif *enumIPv6Interfaces(JNIEnv *env, netif *ifs) { - int sock; - struct lifconf ifc; - struct lifreq *ifr; - int n; - char *buf; - struct lifnum numifs; - unsigned bufsize; - - sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0); - if (sock < 0) { - NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", - "Failed to create IPv6 socket"); - return ifs; - } - - /* - * Get the interface count - */ - numifs.lifn_family = AF_UNSPEC; - numifs.lifn_flags = 0; - if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) { - NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", - "ioctl SIOCGLIFNUM failed"); - close(sock); - return ifs; - } - - /* - * Enumerate the interface configurations - */ - bufsize = numifs.lifn_count * sizeof (struct lifreq); - buf = (char *)malloc(bufsize); - if (!buf) { - JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); - (void) close(sock); - return ifs; - } - ifc.lifc_family = AF_UNSPEC; - ifc.lifc_flags = 0; - ifc.lifc_len = bufsize; - ifc.lifc_buf = buf; - if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) { - NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", - "ioctl SIOCGLIFCONF failed"); - close(sock); - free(buf); - return ifs; - } - - /* - * Iterate through each interface - */ - ifr = ifc.lifc_req; - for (n=0; nlifr_addr.ss_family != AF_INET6) { - continue; - } - - /* - * Get the index - */ - memset((char *)&if2, 0, sizeof(if2)); - strcpy(if2.lifr_name, ifr->lifr_name); - if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) >= 0) { - struct sockaddr_in6 *s6= (struct sockaddr_in6 *)&(ifr->lifr_addr); - index = if2.lifr_index; - s6->sin6_scope_id = index; - } - - /* add to the list */ - ifs = addif(env, ifs, ifr->lifr_name, index, AF_INET6, - (struct sockaddr *)&(ifr->lifr_addr), - sizeof(struct sockaddr_in6), (short) ifr->lifr_addrlen); - - /* - * If an exception occurred we return - */ - if ((*env)->ExceptionOccurred(env)) { - close(sock); - free(buf); - return ifs; - } - - } - - close(sock); - free(buf); - return ifs; - -} -#endif - - -#if defined(__linux__) && defined(AF_INET6) -/* - * Enumerates and returns all IPv6 interfaces on Linux - */ -static netif *enumIPv6Interfaces(JNIEnv *env, netif *ifs) { - FILE *f; - char addr6[40], devname[20]; - char addr6p[8][5]; - int plen, scope, dad_status, if_idx; - uint8_t ipv6addr[16]; - - if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { - while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", - addr6p[0], addr6p[1], addr6p[2], addr6p[3], - addr6p[4], addr6p[5], addr6p[6], addr6p[7], - &if_idx, &plen, &scope, &dad_status, devname) != EOF) { - struct sockaddr_in6 addr; - - sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", - addr6p[0], addr6p[1], addr6p[2], addr6p[3], - addr6p[4], addr6p[5], addr6p[6], addr6p[7]); - inet_pton(AF_INET6, addr6, ipv6addr); - - memset(&addr, 0, sizeof(struct sockaddr_in6)); - memcpy((void*)addr.sin6_addr.s6_addr, (const void*)ipv6addr, 16); - addr.sin6_scope_id = if_idx; - - ifs = addif(env, ifs, devname, if_idx, AF_INET6, - (struct sockaddr *)&addr, - sizeof(struct sockaddr_in6), plen); - - /* - * If an exception occurred then return the list as is. - */ - if ((*env)->ExceptionOccurred(env)) { - fclose(f); - return ifs; - } - } - fclose(f); - } - return ifs; -} -#endif +#define CHECKED_MALLOC3(_pointer,_type,_size) \ + do{ \ + _pointer = (_type)malloc( _size ); \ + if (_pointer == NULL) { \ + JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); \ + return ifs; /* return untouched list */ \ + } \ + } while(0) /* @@ -853,52 +786,43 @@ */ void freeif(netif *ifs) { netif *currif = ifs; + netif *child = NULL; while (currif != NULL) { netaddr *addrP = currif->addr; while (addrP != NULL) { netaddr *next = addrP->next; - if (addrP->addr != NULL) - free(addrP->addr); - if (addrP->brdcast != NULL) - free(addrP->brdcast); free(addrP); addrP = next; - } - - free(currif->name); + } - /* - * Don't forget to free the sub-interfaces. - */ - if (currif->childs != NULL) { - freeif(currif->childs); - } + /* + * Don't forget to free the sub-interfaces. + */ + if (currif->childs != NULL) { + freeif(currif->childs); + } - ifs = currif->next; - free(currif); - currif = ifs; + ifs = currif->next; + free(currif); + currif = ifs; } } -/* - * Add an interface to the list. If known interface just link - * a new netaddr onto the list. If new interface create new - * netif structure. - */ -netif *addif(JNIEnv *env, netif *ifs, char *if_name, int index, int family, - struct sockaddr *new_addrP, int new_addrlen, short prefix) { - netif *currif = ifs, *parent; +netif *addif(JNIEnv *env, int sock, const char * if_name, netif *ifs, struct sockaddr* ifr_addrP, int family, short prefix) { + netif *currif = ifs, *parent; netaddr *addrP; -#ifdef LIFNAMSIZ - char name[LIFNAMSIZ]; - char vname[LIFNAMSIZ]; -#else - char name[IFNAMSIZ]; - char vname[IFNAMSIZ]; -#endif - char *unit; + + #ifdef __solaris__ + char name[LIFNAMSIZ], vname[LIFNAMSIZ]; + #else + char name[IFNAMSIZ], vname[IFNAMSIZ]; + #endif + + char *name_colonP; + int mask; int isVirtual = 0; + int addr_size; /* * If the interface name is a logical interface then we @@ -908,107 +832,63 @@ * logical interfaces. */ strcpy(name, if_name); + *vname = 0; /* * Create and populate the netaddr node. If allocation fails * return an un-updated list. */ - addrP = (netaddr *)malloc(sizeof(netaddr)); - if (addrP) { - addrP->addr = (struct sockaddr *)malloc(new_addrlen); - if (addrP->addr == NULL) { - free(addrP); - addrP = NULL; - } - } - if (addrP == NULL) { - JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); - return ifs; /* return untouched list */ - } - memcpy(addrP->addr, new_addrP, new_addrlen); + /*Allocate for addr and brdcast at once*/ + +#ifdef AF_INET6 + addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); +#else + addr_size = sizeof(struct sockaddr_in); +#endif + + CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr)+2*addr_size); + addrP->addr = (struct sockaddr *)( (char *) addrP+sizeof(netaddr) ); + memcpy(addrP->addr, ifr_addrP, addr_size); + addrP->family = family; - addrP->brdcast = NULL; addrP->mask = prefix; + addrP->next = 0; if (family == AF_INET) { /* * Deal with brodcast addr & subnet mask */ - addrP->brdcast = getBroadcast(env, name); - if (addrP->brdcast) { - addrP->mask = getSubnet(env, name); - } - } + struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size); + addrP->brdcast = getBroadcast(env, sock, name, brdcast_to ); - vname[0] = 0; - unit = strchr(name, ':'); - if (unit != NULL) { + if (addrP->brdcast && (mask = getSubnet(env, sock, name)) != -1) { + addrP->mask = mask; + } + } + + /** + * Deal with virtual interface with colon notaion e.g. eth0:1 + */ + name_colonP = strchr(name, ':'); + if (name_colonP != NULL) { /** * This is a virtual interface. If we are able to access the parent * we need to create a new entry if it doesn't exist yet *and* update * the 'parent' interface with the new records. */ - struct ifreq if2; - int sock; - int len; - - sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - return ifs; /* return untouched list */ - } - - len = unit - name; - if (len > 0) { - // temporarily use vname to hold the parent name of the interface - // instead of creating another buffer. - memcpy(&vname, name, len); - vname[len] = '\0'; - - memset((char *) &if2, 0, sizeof(if2)); - strcpy(if2.ifr_name, vname); - - if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) >= 0) { - // Got access to parent, so create it if necessary. - strcpy(vname, name); - *unit = '\0'; - } else { -#if defined(__solaris__) && defined(AF_INET6) - struct lifreq lifr; - memset((char *) &lifr, 0, sizeof(lifr)); - strcpy(lifr.lifr_name, vname); - - /* Try with an IPv6 socket in case the interface has only IPv6 - * addresses assigned to it */ - close(sock); - sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0); - - if (sock < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - return ifs; /* return untouched list */ - } - - if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) >= 0) { - // Got access to parent, so create it if necessary. - strcpy(vname, name); - *unit = '\0'; - } else { + *name_colonP = 0; + if (getFlags(env,sock,name) < 0) { // failed to access parent interface do not create parent. // We are a virtual interface with no parent. isVirtual = 1; - vname[0] = 0; - } -#else - // failed to access parent interface do not create parent. - // We are a virtual interface with no parent. - isVirtual = 1; - vname[0] = 0; -#endif + *name_colonP = ':'; } - } - close(sock); + else{ + // Got access to parent, so create it if necessary. + // Save original name to vname and truncate name by ':' + memcpy(vname, name, sizeof(vname) ); + vname[name_colonP - name] = ':'; + } } /* @@ -1028,24 +908,15 @@ * insert it onto the list. */ if (currif == NULL) { - currif = (netif *)malloc(sizeof(netif)); - if (currif) { - currif->name = strdup(name); - if (currif->name == NULL) { - free(currif); - currif = NULL; - } - } - if (currif == NULL) { - JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); - return ifs; - } - currif->index = index; - currif->addr = NULL; - currif->childs = NULL; - currif->virtual = isVirtual; - currif->next = ifs; - ifs = currif; + CHECKED_MALLOC3(currif, netif *, sizeof(netif)+IFNAMSIZ ); + currif->name = (char *) currif+sizeof(netif); + strcpy(currif->name, name); + currif->index = getIndex(sock, name); + currif->addr = NULL; + currif->childs = NULL; + currif->virtual = isVirtual; + currif->next = ifs; + ifs = currif; } /* @@ -1060,161 +931,251 @@ * Let's deal with the virtual interface now. */ if (vname[0]) { - netaddr *tmpaddr; + netaddr *tmpaddr; - currif = parent->childs; + currif = parent->childs; - while (currif != NULL) { - if (strcmp(vname, currif->name) == 0) { - break; - } - currif = currif->next; - } - if (currif == NULL) { - currif = (netif *)malloc(sizeof(netif)); - if (currif) { - currif->name = strdup(vname); - if (currif->name == NULL) { - free(currif); - currif = NULL; - } - } - if (currif == NULL) { - JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); - return ifs; + while (currif != NULL) { + if (strcmp(vname, currif->name) == 0) { + break; + } + currif = currif->next; } - currif->index = index; - currif->addr = NULL; - /* Need to duplicate the addr entry? */ - currif->virtual = 1; - currif->childs = NULL; - currif->next = parent->childs; - parent->childs = currif; - } + + if (currif == NULL) { + CHECKED_MALLOC3(currif, netif *, sizeof(netif)+ IFNAMSIZ ); + currif->name = (char *) currif + sizeof(netif); + strcpy(currif->name, vname); + currif->index = getIndex(sock, vname); + currif->addr = NULL; + /* Need to duplicate the addr entry? */ + currif->virtual = 1; + currif->childs = NULL; + currif->next = parent->childs; + parent->childs = currif; + } - tmpaddr = (netaddr *) malloc(sizeof(netaddr)); - if (tmpaddr == NULL) { - JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); - return ifs; - } - memcpy(tmpaddr, addrP, sizeof(netaddr)); - /** - * Let's duplicate the address and broadcast address structures - * if there are any. - */ - if (addrP->addr != NULL) { - tmpaddr->addr = malloc(new_addrlen); - if (tmpaddr->addr != NULL) - memcpy(tmpaddr->addr, addrP->addr, new_addrlen); - } - if (addrP->brdcast != NULL) { - tmpaddr->brdcast = malloc(new_addrlen); - if (tmpaddr->brdcast != NULL) - memcpy(tmpaddr->brdcast, addrP->brdcast, new_addrlen); - } - tmpaddr->next = currif->addr; - currif->addr = tmpaddr; + CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr)+2*addr_size); + memcpy(tmpaddr, addrP, sizeof(netaddr)); + if (addrP->addr != NULL) { + tmpaddr->addr = (struct sockaddr *) ( (char*)tmpaddr + sizeof(netaddr) ) ; + memcpy(tmpaddr->addr, addrP->addr, addr_size); + } + + if (addrP->brdcast != NULL) { + tmpaddr->brdcast = (struct sockaddr *) ((char *) tmpaddr + sizeof(netaddr)+addr_size); + memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size); + } + + tmpaddr->next = currif->addr; + currif->addr = tmpaddr; } return ifs; } -/** - * Get flags from a NetworkInterface. +/* Open socket for further ioct calls + * proto is AF_INET/AF_INET6 */ -static short getFlags(JNIEnv *env, jstring name) { - int sock; - struct ifreq if2; - jboolean isCopy; - const char* name_utf; - short ret = -1; +static int openSocket(JNIEnv *env, int proto){ + int sock; + + if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) { + /* + * If EPROTONOSUPPORT is returned it means we don't have + * support for this proto so don't throw an exception. + */ + if (errno != EPROTONOSUPPORT) { + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "Socket creation failed"); + } + return -1; + } - sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - return -1; - } + return sock; +} + + +/** Linux **/ +#ifdef __linux__ +/* Open socket for further ioct calls, try v4 socket first and + * if it falls return v6 socket + */ + +#ifdef AF_INET6 +static int openSocketWithFallback(JNIEnv *env, const char *ifname){ + int sock; + struct ifreq if2; - name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); - memset((char *) &if2, 0, sizeof(if2)); - strcpy(if2.ifr_name, name_utf); + if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if (errno == EPROTONOSUPPORT){ + if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){ + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); + return -1; + } + } + else{ // errno is not NOSUPPORT + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed"); + return -1; + } + } + + /* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type + of address of an interface */ + + return sock; +} + +#else +static int openSocketWithFallback(JNIEnv *env, const char *ifname){ + return openSocket(env,AF_INET); +} +#endif - if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) >= 0) { - ret = if2.ifr_flags; - } else { -#if defined(__solaris__) && defined(AF_INET6) - /* Try with an IPv6 socket in case the interface has only IPv6 addresses assigned to it */ - struct lifreq lifr; +static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { + struct ifconf ifc; + struct ifreq *ifreqP; + char *buf; + int numifs; + unsigned i; + - close(sock); - sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0); + /* need to do a dummy SIOCGIFCONF to determine the buffer size. + * SIOCGIFCOUNT doesn't work + */ + ifc.ifc_buf = NULL; + if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed"); + return ifs; + } - if (sock < 0) { - (*env)->ReleaseStringUTFChars(env, name, name_utf); - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - return -1; + CHECKED_MALLOC3(buf,char *, ifc.ifc_len); + + ifc.ifc_buf = buf; + if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed"); + (void) free(buf); + return ifs; } - memset((caddr_t)&lifr, 0, sizeof(lifr)); - strcpy((caddr_t)&(lifr.lifr_name), name_utf); + /* + * Iterate through each interface + */ + ifreqP = ifc.ifc_req; + for (i=0; iifr_name, ifs, (struct sockaddr *) & (ifreqP->ifr_addr), AF_INET, 0); - if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) >= 0) { - ret = lifr.lifr_flags; - } else { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "IOCTL failed"); + /* + * If an exception occurred then free the list + */ + if ((*env)->ExceptionOccurred(env)) { + free(buf); + freeif(ifs); + return NULL; + } } -#else - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "IOCTL failed"); + + /* + * Free socket and buffer + */ + free(buf); + return ifs; +} + + +/* + * Enumerates and returns all IPv6 interfaces on Linux + */ + +#ifdef AF_INET6 +static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { + FILE *f; + char addr6[40], devname[20]; + char addr6p[8][5]; + int plen, scope, dad_status, if_idx; + uint8_t ipv6addr[16]; + + if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { + while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7], + &if_idx, &plen, &scope, &dad_status, devname) != EOF) { + + struct netif *ifs_ptr = NULL; + struct netif *last_ptr = NULL; + struct sockaddr_in6 addr; + + sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]); + inet_pton(AF_INET6, addr6, ipv6addr); + + memset(&addr, 0, sizeof(struct sockaddr_in6)); + memcpy((void*)addr.sin6_addr.s6_addr, (const void*)ipv6addr, 16); + + addr.sin6_scope_id = if_idx; + + ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr, AF_INET6, plen); + + + /* + * If an exception occurred then return the list as is. + */ + if ((*env)->ExceptionOccurred(env)) { + fclose(f); + return ifs; + } + } + fclose(f); + } + return ifs; +} #endif - } - close(sock); - /* release the UTF string and interface list */ - (*env)->ReleaseStringUTFChars(env, name, name_utf); + - return ret; +static int getIndex(int sock, const char *name){ + /* + * Try to get the interface index + * (Not supported on Solaris 2.6 or 7) + */ + struct ifreq if2; + strcpy(if2.ifr_name, name); + + if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) { + return -1; + } + + return if2.ifr_ifindex; } /** * Returns the IPv4 broadcast address of a named interface, if it exists. * Returns 0 if it doesn't have one. */ -static struct sockaddr *getBroadcast(JNIEnv *env, const char *ifname) { - int sock; +static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) { struct sockaddr *ret = NULL; struct ifreq if2; - short flag = 0; - - sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - return ret; - } memset((char *) &if2, 0, sizeof(if2)); strcpy(if2.ifr_name, ifname); + /* Let's make sure the interface does have a broadcast address */ - if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) >= 0) { - flag = if2.ifr_flags; - } else { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "IOCTL failed"); + if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFFLAGS failed"); + return ret; } - if (flag & IFF_BROADCAST) { - /* It does, let's retrieve it*/ - if (ioctl(sock, SIOCGIFBRDADDR, (char *)&if2) >= 0) { - ret = (struct sockaddr*) malloc(sizeof(struct sockaddr)); + + if (if2.ifr_flags & IFF_BROADCAST) { + /* It does, let's retrieve it*/ + if (ioctl(sock, SIOCGIFBRDADDR, (char *)&if2) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFBRDADDR failed"); + return ret; + } + + ret = brdcast_store; memcpy(ret, &if2.ifr_broadaddr, sizeof(struct sockaddr)); - } else { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "IOCTL failed"); - } } - close(sock); + return ret; } @@ -1222,39 +1183,314 @@ * Returns the IPv4 subnet prefix length (aka subnet mask) for the named * interface, if it has one, otherwise return -1. */ -static short getSubnet(JNIEnv *env, const char *ifname) { - int sock; - unsigned int mask; - short ret; - struct ifreq if2; +static short getSubnet(JNIEnv *env, int sock, const char *ifname) { + unsigned int mask; + short ret; + struct ifreq if2; + + memset((char *) &if2, 0, sizeof(if2)); + strcpy(if2.ifr_name, ifname); + + if (ioctl(sock, SIOCGIFNETMASK, (char *)&if2) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFNETMASK failed"); + return -1; + } + + mask = ntohl(((struct sockaddr_in*)&(if2.ifr_addr))->sin_addr.s_addr); + ret = 0; + while (mask) { + mask <<= 1; + ret++; + } + + return ret; +} + +/** + * Get the Hardware address (usually MAC address) for the named interface. + * return puts the data in buf, and returns the length, in byte, of the + * MAC address. Returns -1 if there is no hardware address on that interface. + */ +static int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf) { + static struct ifreq ifr; + int i; - sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); + strcpy(ifr.ifr_name, ifname); + if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFHWADDR failed"); + return -1; + } + + memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN); + + /* + * All bytes to 0 means no hardware address. + */ + + for (i = 0; i < IFHWADDRLEN; i++) { + if (buf[i] != 0) + return IFHWADDRLEN; + } + return -1; - } +} + +static int getMTU(JNIEnv *env, int sock, const char *ifname) { + struct ifreq if2; + + memset((char *) &if2, 0, sizeof(if2)); + strcpy(if2.ifr_name, ifname); + + if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed"); + return -1; + } + + return if2.ifr_mtu; +} + +static int getFlags(JNIEnv *env, int sock, const char *ifname) { + struct ifreq if2; + int ret = -1; memset((char *) &if2, 0, sizeof(if2)); strcpy(if2.ifr_name, ifname); - if (ioctl(sock, SIOCGIFNETMASK, (char *)&if2) >= 0) { - mask = ntohl(((struct sockaddr_in*)&(if2.ifr_addr))->sin_addr.s_addr); - ret = 0; - while (mask) { - mask <<= 1; - ret++; + + if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0){ + return -1; + } + + return if2.ifr_flags; +} + +#endif + +/** Solaris **/ +#ifdef __solaris__ +/* Open socket for further ioct calls, try v4 socket first and + * if it falls return v6 socket + */ + +#ifdef AF_INET6 +static int openSocketWithFallback(JNIEnv *env, const char *ifname){ + int sock, alreadyV6 = 0; + struct lifreq if2; + + if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if (errno == EPROTONOSUPPORT){ + if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){ + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); + return -1; + } + + alreadyV6=1; + } + else{ // errno is not NOSUPPORT + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed"); + return -1; + } + } + + /** + * Solaris requires that we have IPv6 socket to query an + * interface without IPv4 address - check it here + * POSIX 1 require the kernell to return ENOTTY if the call is + * unappropriate for device e.g. NETMASK for device having IPv6 + * only address but not all devices follows the standart so + * fallback on any error. It's not an ecology friendly but more + * reliable. + */ + + if (! alreadyV6 ){ + memset((char *) &if2, 0, sizeof(if2)); + strcpy(if2.lifr_name, ifname); + if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { + close(sock); + if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){ + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); + return -1; + } + } } - close(sock); - return ret; - } - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "IOCTL failed"); - close(sock); - return -1; + + return sock; +} + +#else +static int openSocketWithFallback(JNIEnv *env, const char *ifname){ + return openSocket(env,AF_INET); +} +#endif + +/* + * Enumerates and returns all IPv4 interfaces + * (linux verison) + */ + +static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { + return enumIPvXInterfaces(env,sock, ifs, AF_INET); } -#ifdef __solaris__ -#define DEV_PREFIX "/dev/" +#ifdef AF_INET6 +static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { + return enumIPvXInterfaces(env,sock, ifs, AF_INET6); +} +#endif + +/* + Enumerates and returns all interfaces on Solaris + use the same code for IPv4 and IPv6 + */ +static netif *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family) { + struct lifconf ifc; + struct lifreq *ifr; + int n; + char *buf; + struct lifnum numifs; + unsigned bufsize; + + /* + * Get the interface count + */ + numifs.lifn_family = family; + numifs.lifn_flags = 0; + if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) { + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGLIFNUM failed"); + return ifs; + } + + /* + * Enumerate the interface configurations + */ + bufsize = numifs.lifn_count * sizeof (struct lifreq); + CHECKED_MALLOC3(buf, char *, bufsize); + + ifc.lifc_family = family; + ifc.lifc_flags = 0; + ifc.lifc_len = bufsize; + ifc.lifc_buf = buf; + if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) { + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGLIFCONF failed"); + free(buf); + return ifs; + } + + /* + * Iterate through each interface + */ + ifr = ifc.lifc_req; + for (n=0; nlifr_addr.ss_family != family) { + continue; + } + +#ifdef AF_INET6 + if (ifr->lifr_addr.ss_family == AF_INET6) { + struct sockaddr_in6 *s6= (struct sockaddr_in6 *)&(ifr->lifr_addr); + s6->sin6_scope_id = getIndex(sock, ifr->lifr_name); + } +#endif + + /* add to the list */ + ifs = addif(env, sock,ifr->lifr_name, ifs, (struct sockaddr *)&(ifr->lifr_addr),family, (short) ifr->lifr_addrlen); + + /* + * If an exception occurred we return immediately + */ + if ((*env)->ExceptionOccurred(env)) { + free(buf); + return ifs; + } + + } + + free(buf); + return ifs; +} + +static int getIndex(int sock, const char *name){ + /* + * Try to get the interface index + * (Not supported on Solaris 2.6 or 7) + */ + struct lifreq if2; + strcpy(if2.lifr_name, name); + + if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) < 0) { + return -1; + } + + return if2.lifr_index; +} + +/** + * Returns the IPv4 broadcast address of a named interface, if it exists. + * Returns 0 if it doesn't have one. + */ +static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) { + struct sockaddr *ret = NULL; + struct lifreq if2; + + memset((char *) &if2, 0, sizeof(if2)); + strcpy(if2.lifr_name, ifname); + + /* Let's make sure the interface does have a broadcast address */ + if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFFLAGS failed"); + return ret; + } + + if (if2.lifr_flags & IFF_BROADCAST) { + /* It does, let's retrieve it*/ + if (ioctl(sock, SIOCGLIFBRDADDR, (char *)&if2) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFBRDADDR failed"); + return ret; + } + + ret = brdcast_store; + memcpy(ret, &if2.lifr_broadaddr, sizeof(struct sockaddr)); + } + + return ret; +} + +/** + * Returns the IPv4 subnet prefix length (aka subnet mask) for the named + * interface, if it has one, otherwise return -1. + */ +static short getSubnet(JNIEnv *env, int sock, const char *ifname) { + unsigned int mask; + short ret; + struct lifreq if2; + + memset((char *) &if2, 0, sizeof(if2)); + strcpy(if2.lifr_name, ifname); + + if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFNETMASK failed"); + return -1; + } + + mask = ntohl(((struct sockaddr_in*)&(if2.lifr_addr))->sin_addr.s_addr); + ret = 0; + + while (mask) { + mask <<= 1; + ret++; + } + + return ret; +} + + + +#define DEV_PREFIX "/dev/" /** * Solaris specific DLPI code to get hardware address from a device. @@ -1262,306 +1498,147 @@ * privileges (i.e. be root). */ static int getMacFromDevice(JNIEnv *env, const char* ifname, unsigned char* retbuf) { - char style1dev[MAXPATHLEN]; - int fd; - dl_phys_addr_req_t dlpareq; - dl_phys_addr_ack_t *dlpaack; - struct strbuf msg; - char buf[128]; - int flags = 0; + char style1dev[MAXPATHLEN]; + int fd; + dl_phys_addr_req_t dlpareq; + dl_phys_addr_ack_t *dlpaack; + struct strbuf msg; + char buf[128]; + int flags = 0; + + /** + * Device is in /dev + * e.g.: /dev/bge0 + */ + strcpy(style1dev, DEV_PREFIX); + strcat(style1dev, ifname); + if ((fd = open(style1dev, O_RDWR)) < 0) { + /* + * Can't open it. We probably are missing the privilege. + * We'll have to try something else + */ + return 0; + } + + dlpareq.dl_primitive = DL_PHYS_ADDR_REQ; + dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR; - /** - * Device is in /dev - * e.g.: /dev/bge0 - */ - strcpy(style1dev, DEV_PREFIX); - strcat(style1dev, ifname); - if ((fd = open(style1dev, O_RDWR)) == -1) { - /* - * Can't open it. We probably are missing the privilege. - * We'll have to try something else - */ - return 0; - } - dlpareq.dl_primitive = DL_PHYS_ADDR_REQ; - dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR; - msg.buf = (char *)&dlpareq; - msg.len = DL_PHYS_ADDR_REQ_SIZE; - if (putmsg(fd, &msg, NULL, 0) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "putmsg failed"); - return -1; - } - dlpaack = (dl_phys_addr_ack_t *)buf; - msg.buf = (char *)buf; - msg.len = 0; - msg.maxlen = sizeof (buf); - if (getmsg(fd, &msg, NULL, &flags) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "getmsg failed"); - return -1; - } - if (msg.len < DL_PHYS_ADDR_ACK_SIZE || - dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) { - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", - "Couldn't obtain phys addr\n"); - return -1; - } + msg.buf = (char *)&dlpareq; + msg.len = DL_PHYS_ADDR_REQ_SIZE; + + if (putmsg(fd, &msg, NULL, 0) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "putmsg failed"); + return -1; + } + + dlpaack = (dl_phys_addr_ack_t *)buf; - memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length); - return dlpaack->dl_addr_length; + msg.buf = (char *)buf; + msg.len = 0; + msg.maxlen = sizeof (buf); + if (getmsg(fd, &msg, NULL, &flags) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "getmsg failed"); + return -1; + } + + if (msg.len < DL_PHYS_ADDR_ACK_SIZE || dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Couldn't obtain phys addr\n"); + return -1; + } + + memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length); + return dlpaack->dl_addr_length; } -#endif /** * Get the Hardware address (usually MAC address) for the named interface. * return puts the data in buf, and returns the length, in byte, of the * MAC address. Returns -1 if there is no hardware address on that interface. */ -int getMacAddress(JNIEnv *env, const struct in_addr* addr, const char* ifname, - unsigned char *buf) { - int sock; -#ifdef __linux__ - static struct ifreq ifr; - int i; +static int getMacAddress(JNIEnv *env, int sock, const char *ifname, const struct in_addr* addr, unsigned char *buf) { + struct arpreq arpreq; + struct sockaddr_in* sin; + struct sockaddr_in ipAddr; + int len, i; + + /** + * On Solaris we have to use DLPI, but it will only work if we have + * privileged access (i.e. root). If that fails, we try a lookup + * in the ARP table, which requires an IPv4 address. + */ + if ((len = getMacFromDevice(env, ifname, buf)) == 0) { + /*DLPI failed - trying to do arp lookup*/ + + if (addr == NULL) { + /** + * No IPv4 address for that interface, so can't do an ARP lookup. + */ + return -1; + } - sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0); + len = 6; //??? + + sin = (struct sockaddr_in *) &arpreq.arp_pa; + memset((char *) &arpreq, 0, sizeof(struct arpreq)); + ipAddr.sin_port = 0; + ipAddr.sin_family = AF_INET; + memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr)); + memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in)); + arpreq.arp_flags= ATF_PUBL; - if (sock < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - return -1; + if (ioctl(sock, SIOCGARP, &arpreq) < 0) { + if (errno != ENXIO) { + // "No such device or address" means no hardware address, so it's + // normal don't throw an exception + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL failed"); + return -1; + } + } + + memcpy(buf, &arpreq.arp_ha.sa_data[0], len ); } - strcpy(ifr.ifr_name, ifname); - - if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) { - fprintf(stderr, "SIOCIFHWADDR: %s\n", - strerror(errno)); - close(sock); - return -1; - } - memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN); - close(sock); - for (i = 0; i < IFHWADDRLEN; i++) { - if (buf[i] != 0) - return IFHWADDRLEN; - } - /* - * All bytes to 0 means no hardware address. - */ - return -1; -#else - struct arpreq arpreq; - struct sockaddr_in* sin; - struct sockaddr_in ipAddr; - int len; - - /** - * On Solaris we have to use DLPI, but it will only work if we have - * privileged access (i.e. root). If that fails, we try a lookup - * in the ARP table, which requires an IPv4 address. - */ - if ((len = getMacFromDevice(env, ifname, buf)) > 0) { - return len; - } - if (addr == NULL) { - /** - * No IPv4 address for that interface, so can't do an ARP lookup. + /* + * All bytes to 0 means no hardware address. */ - return -1; - } - sin = (struct sockaddr_in *) &arpreq.arp_pa; - memset((char *) &arpreq, 0, sizeof(struct arpreq)); - ipAddr.sin_port = 0; - ipAddr.sin_family = AF_INET; - memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr)); - memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in)); - arpreq.arp_flags= ATF_PUBL; - sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0); - - if (sock < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - return -1; - } - if (ioctl(sock, SIOCGARP, &arpreq) >= 0) { - close(sock); - memcpy(buf, &arpreq.arp_ha.sa_data[0], 6); - return 6; - } - - if (errno != ENXIO) { - // "No such device or address" means no hardware address, so it's - // normal don't throw an exception - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "IOCTL failed"); - } - close(sock); -#endif - return -1; -} - -/* - * Class: java_net_NetworkInterface - * Method: isUp0 - * Signature: (Ljava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0 - (JNIEnv *env, jclass cls, jstring name, jint index) { - short val; + for (i = 0; i < len; i++) { + if (buf[i] != 0) + return len; + } - val = getFlags(env, name); - if ( (val & IFF_UP) && (val & IFF_RUNNING)) - return JNI_TRUE; - return JNI_FALSE; -} - -/* - * Class: java_net_NetworkInterface - * Method: isP2P0 - * Signature: (Ljava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0 - (JNIEnv *env, jclass cls, jstring name, jint index) { - if (getFlags(env, name) & IFF_POINTOPOINT) - return JNI_TRUE; - return JNI_FALSE; -} - -/* - * Class: java_net_NetworkInterface - * Method: isLoopback0 - * Signature: (Ljava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0 - (JNIEnv *env, jclass cls, jstring name, jint index) { - if (getFlags(env, name) & IFF_LOOPBACK) - return JNI_TRUE; - return JNI_FALSE; + return -1; } -/* - * Class: java_net_NetworkInterface - * Method: supportsMulticast0 - * Signature: (Ljava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0 -(JNIEnv *env, jclass cls, jstring name, jint index) { - short val; +static int getMTU(JNIEnv *env, int sock, const char *ifname) { + struct lifreq if2; - val = getFlags(env, name); - if (val & IFF_MULTICAST) - return JNI_TRUE; - return JNI_FALSE; -} + memset((char *) &if2, 0, sizeof(if2)); + strcpy(if2.lifr_name, ifname); -/* - * Class: java_net_NetworkInterface - * Method: getMacAddr0 - * Signature: ([bLjava/lang/String;I)[b - */ -JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0(JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) { - jint addr; - jbyte caddr[4]; - struct in_addr iaddr; - jbyteArray ret = NULL; - unsigned char mac[16]; - int len; - jboolean isCopy; - const char* name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); + if (ioctl(sock, SIOCGLIFMTU, (char *)&if2) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFMTU failed"); + return -1; + } - if (!IS_NULL(addrArray)) { - (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); - addr = ((caddr[0]<<24) & 0xff000000); - addr |= ((caddr[1] <<16) & 0xff0000); - addr |= ((caddr[2] <<8) & 0xff00); - addr |= (caddr[3] & 0xff); - iaddr.s_addr = htonl(addr); - len = getMacAddress(env, &iaddr, name_utf, mac); - } else { - len = getMacAddress(env, NULL, name_utf, mac); - } - if (len > 0) { - ret = (*env)->NewByteArray(env, len); - if (IS_NULL(ret)) { - /* we may have memory to free at the end of this */ - goto fexit; - } - (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) (mac)); - } - fexit: - /* release the UTF string and interface list */ - (*env)->ReleaseStringUTFChars(env, name, name_utf); - return ret; + return if2.lifr_mtu; } -/* - * Class: java_net_NetworkInterface - * Method: getMTU0 - * Signature: ([bLjava/lang/String;I)I - */ -JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) { - jboolean isCopy; - int sock; - struct ifreq if2; - int ret = -1; - const char* name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); - - sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - } else { - -#ifdef __linux__ - memset((char *) &if2, 0, sizeof(if2)); - strcpy(if2.ifr_name, name_utf); +static int getFlags(JNIEnv *env, int sock, const char *ifname) { + struct lifreq lifr; + memset((caddr_t)&lifr, 0, sizeof(lifr)); + strcpy((caddr_t)&(lifr.lifr_name), ifname); - if (ioctl(sock, SIOCGIFMTU, (char *)&if2) >= 0) { - ret= if2.ifr_mtu; - } else { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "IOCTL failed"); - } -#else /* Solaris */ - struct lifreq lifr; - memset((caddr_t)&lifr, 0, sizeof(lifr)); - strcpy((caddr_t)&(lifr.lifr_name), name_utf); - if (ioctl(sock, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) { - ret = lifr.lifr_mtu; -#ifdef AF_INET6 - } else { - /* Try wIth an IPv6 socket in case the interface has only IPv6 addresses assigned to it */ - close(sock); - sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0); + if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFFLAGS failed"); + return -1; + } - if (sock < 0) { - (*env)->ReleaseStringUTFChars(env, name, name_utf); - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Socket creation failed"); - return -1; - } + return lifr.lifr_flags; +} + - if (ioctl(sock, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) { - ret = lifr.lifr_mtu; - } else { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "IOCTL failed"); - } - } -#else - } else { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "IOCTL failed"); - } #endif -#endif - close(sock); - } - /* release the UTF string and interface list */ - (*env)->ReleaseStringUTFChars(env, name, name_utf); - return ret; -} + + diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c --- a/jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c Wed Jul 05 17:18:12 2017 +0200 @@ -42,6 +42,29 @@ filename); } +static void quit(gboolean isSignalHandler) +{ + if (dialog != NULL) + { + // Callbacks from GTK signals are made within the GTK lock + // So, within a signal handler there is no need to call + // gdk_threads_enter() / fp_gdk_threads_leave() + if (!isSignalHandler) { + fp_gdk_threads_enter(); + } + + fp_gtk_widget_hide (dialog); + fp_gtk_widget_destroy (dialog); + + fp_gtk_main_quit (); + dialog = NULL; + + if (!isSignalHandler) { + fp_gdk_threads_leave(); + } + } +} + /* * Class: sun_awt_X11_GtkFileDialogPeer * Method: quit @@ -50,18 +73,7 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit (JNIEnv * env, jobject jpeer) { - if (dialog != NULL) - { - fp_gdk_threads_enter(); - - fp_gtk_widget_hide (dialog); - fp_gtk_widget_destroy (dialog); - - fp_gtk_main_quit (); - dialog = NULL; - - fp_gdk_threads_leave(); - } + quit(FALSE); } /** @@ -147,7 +159,7 @@ jfilenames); fp_g_free(current_folder); - Java_sun_awt_X11_GtkFileDialogPeer_quit(NULL, NULL); + quit(TRUE); } /* diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c --- a/jdk/src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c Wed Jul 05 17:18:12 2017 +0200 @@ -65,6 +65,11 @@ J2dTraceLn(J2D_TRACE_INFO, "GLXSurfaceData_initOps"); + if (oglsdo == NULL) { + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); + return; + } + if (glxsdo == NULL) { JNU_ThrowOutOfMemoryError(env, "creating native GLX ops"); return; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c --- a/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c Wed Jul 05 17:18:12 2017 +0200 @@ -253,6 +253,10 @@ { #ifndef HEADLESS X11SDOps *xsdo = (X11SDOps*)SurfaceData_InitOps(env, xsd, sizeof(X11SDOps)); + if (xsdo == NULL) { + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); + return; + } xsdo->sdOps.Lock = X11SD_Lock; xsdo->sdOps.GetRasInfo = X11SD_GetRasInfo; xsdo->sdOps.Unlock = X11SD_Unlock; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/windows/bin/java_md.c --- a/jdk/src/windows/bin/java_md.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/windows/bin/java_md.c Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,26 +80,22 @@ * */ void -CreateExecutionEnvironment(int *_argc, - char ***_argv, - char jrepath[], - jint so_jrepath, - char jvmpath[], - jint so_jvmpath, - char **original_argv) { +CreateExecutionEnvironment(int *pargc, char ***pargv, + char *jrepath, jint so_jrepath, + char *jvmpath, jint so_jvmpath) { char * jvmtype; int i = 0; - char** pargv = *_argv; int running = CURRENT_DATA_MODEL; int wanted = running; - for (i = 0; i < *_argc ; i++) { - if (JLI_StrCmp(pargv[i], "-J-d64") == 0 || JLI_StrCmp(pargv[i], "-d64") == 0) { + char** argv = *pargv; + for (i = 0; i < *pargc ; i++) { + if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) { wanted = 64; continue; } - if (JLI_StrCmp(pargv[i], "-J-d32") == 0 || JLI_StrCmp(pargv[i], "-d32") == 0) { + if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) { wanted = 32; continue; } @@ -123,7 +119,12 @@ JLI_ReportErrorMessage(CFG_ERROR7); exit(1); } - jvmtype = CheckJvmType(_argc, _argv, JNI_FALSE); + + jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE); + if (JLI_StrCmp(jvmtype, "ERROR") == 0) { + JLI_ReportErrorMessage(CFG_ERROR9); + exit(4); + } jvmpath[0] = '\0'; if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { @@ -131,7 +132,6 @@ exit(4); } /* If we got here, jvmpath has been correctly initialized. */ - } @@ -203,19 +203,21 @@ PREJVMSTART PreJVMStart; struct stat s; + /* Make sure the jrepath contains something */ + if (jrepath[0] == NULL) { + return; + } /* 32 bit windows only please */ - if (strcmp(GetArch(), "i386") != 0 ) { + if (JLI_StrCmp(GetArch(), "i386") != 0 ) { return; } /* Does our bundle directory exist ? */ - strcpy(tmpbuf, jrepath); - strcat(tmpbuf, "\\lib\\bundles"); + JLI_Snprintf(tmpbuf, sizeof(tmpbuf), "%s\\lib\\bundles", jrepath); if (stat(tmpbuf, &s) != 0) { return; } /* Does our jkernel dll exist ? */ - strcpy(tmpbuf, jrepath); - strcat(tmpbuf, "\\bin\\jkernel.dll"); + JLI_Snprintf(tmpbuf, sizeof(tmpbuf), "%s\\bin\\jkernel.dll", jrepath); if (stat(tmpbuf, &s) != 0) { return; } @@ -249,30 +251,30 @@ if (GetApplicationHome(path, pathsize)) { /* Is JRE co-located with the application? */ - sprintf(javadll, "%s\\bin\\" JAVA_DLL, path); + JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path); if (stat(javadll, &s) == 0) { - goto found; + JLI_TraceLauncher("JRE path is %s\n", path); + return JNI_TRUE; } /* Does this app ship a private JRE in \jre directory? */ - sprintf(javadll, "%s\\jre\\bin\\" JAVA_DLL, path); + JLI_Snprintf(javadll, sizeof (javadll), "%s\\jre\\bin\\" JAVA_DLL, path); if (stat(javadll, &s) == 0) { JLI_StrCat(path, "\\jre"); - goto found; + JLI_TraceLauncher("JRE path is %s\n", path); + return JNI_TRUE; } } /* Look for a public JRE on this machine. */ if (GetPublicJREHome(path, pathsize)) { - goto found; + JLI_TraceLauncher("JRE path is %s\n", path); + return JNI_TRUE; } JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; - found: - JLI_TraceLauncher("JRE path is %s\n", path); - return JNI_TRUE; } /* @@ -286,9 +288,9 @@ { struct stat s; if (JLI_StrChr(jvmtype, '/') || JLI_StrChr(jvmtype, '\\')) { - sprintf(jvmpath, "%s\\" JVM_DLL, jvmtype); + JLI_Snprintf(jvmpath, jvmpathsize, "%s\\" JVM_DLL, jvmtype); } else { - sprintf(jvmpath, "%s\\bin\\%s\\" JVM_DLL, jrepath, jvmtype); + JLI_Snprintf(jvmpath, jvmpathsize, "%s\\bin\\%s\\" JVM_DLL, jrepath, jvmtype); } if (stat(jvmpath, &s) == 0) { return JNI_TRUE; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java --- a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Wed Jul 05 17:18:12 2017 +0200 @@ -312,14 +312,17 @@ private int processSelectedKeys(long updateCount) { int numKeysUpdated = 0; numKeysUpdated += processFDSet(updateCount, readFds, - PollArrayWrapper.POLLIN); + PollArrayWrapper.POLLIN, + false); numKeysUpdated += processFDSet(updateCount, writeFds, PollArrayWrapper.POLLCONN | - PollArrayWrapper.POLLOUT); + PollArrayWrapper.POLLOUT, + false); numKeysUpdated += processFDSet(updateCount, exceptFds, PollArrayWrapper.POLLIN | PollArrayWrapper.POLLCONN | - PollArrayWrapper.POLLOUT); + PollArrayWrapper.POLLOUT, + true); return numKeysUpdated; } @@ -331,7 +334,9 @@ * * me.updateCount <= me.clearedCount <= updateCount */ - private int processFDSet(long updateCount, int[] fds, int rOps) { + private int processFDSet(long updateCount, int[] fds, int rOps, + boolean isExceptFds) + { int numKeysUpdated = 0; for (int i = 1; i <= fds[0]; i++) { int desc = fds[i]; @@ -347,6 +352,17 @@ if (me == null) continue; SelectionKeyImpl sk = me.ski; + + // The descriptor may be in the exceptfds set because there is + // OOB data queued to the socket. If there is OOB data then it + // is discarded and the key is not added to the selected set. + if (isExceptFds && + (sk.channel() instanceof SocketChannelImpl) && + discardUrgentData(desc)) + { + continue; + } + if (selectedKeys.contains(sk)) { // Key in selected set if (me.clearedCount != updateCount) { if (sk.channel.translateAndSetReadyOps(rOps, sk) && @@ -460,6 +476,8 @@ private native void resetWakeupSocket0(int wakeupSourceFd); + private native boolean discardUrgentData(int fd); + // We increment this counter on each call to updateSelectedKeys() // each entry in SubSelector.fdsMap has a memorized value of // updateCount. When we increment numKeysUpdated we set updateCount diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/windows/native/sun/java2d/opengl/WGLSurfaceData.c --- a/jdk/src/windows/native/sun/java2d/opengl/WGLSurfaceData.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/windows/native/sun/java2d/opengl/WGLSurfaceData.c Wed Jul 05 17:18:12 2017 +0200 @@ -66,6 +66,10 @@ J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_initOps"); + if (oglsdo == NULL) { + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); + return; + } if (wglsdo == NULL) { JNU_ThrowOutOfMemoryError(env, "creating native wgl ops"); return; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.cpp --- a/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.cpp Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.cpp Wed Jul 05 17:18:12 2017 +0200 @@ -363,6 +363,10 @@ { J2dTraceLn(J2D_TRACE_INFO, "GDIWindowSurfaceData_initOps"); GDIWinSDOps *wsdo = (GDIWinSDOps *)SurfaceData_InitOps(env, wsd, sizeof(GDIWinSDOps)); + if (wsdo == NULL) { + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); + return; + } wsdo->sdOps.Lock = GDIWinSD_Lock; wsdo->sdOps.GetRasInfo = GDIWinSD_GetRasInfo; wsdo->sdOps.Unlock = GDIWinSD_Unlock; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c --- a/jdk/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c Wed Jul 05 17:18:12 2017 +0200 @@ -214,3 +214,19 @@ recv(scinFd, bytes, WAKEUP_SOCKET_BUF_SIZE, 0); } } + +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_WindowsSelectorImpl_discardUrgentData(JNIEnv* env, jobject this, + jint s) +{ + char data[8]; + jboolean discarded = JNI_FALSE; + int n; + do { + n = recv(s, &data, sizeof(data), MSG_OOB); + if (n > 0) { + discarded = JNI_TRUE; + } + } while (n > 0); + return discarded; +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/Makefile --- a/jdk/test/Makefile Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/Makefile Wed Jul 05 17:18:12 2017 +0200 @@ -495,19 +495,17 @@ jdk_nio1: java/nio/file $(call RunSamevmBatch) -# Stable othervm testruns (minus items from PROBLEM_LIST) -# Using samevm has serious problems with these tests +# Stable samevm testruns (minus items from PROBLEM_LIST) JDK_ALL_TARGETS += jdk_nio2 jdk_nio2: java/nio/Buffer java/nio/ByteOrder \ java/nio/channels java/nio/BufferPoolMXBean java/nio/MappedByteBuffer $(call SharedLibraryPermissions,java/nio/channels) - $(call RunOthervmBatch) + $(call RunSamevmBatch) -# Stable othervm testruns (minus items from PROBLEM_LIST) -# Using samevm has serious problems with these tests +# Stable samevm testruns (minus items from PROBLEM_LIST) JDK_ALL_TARGETS += jdk_nio3 jdk_nio3: com/sun/nio sun/nio - $(call RunOthervmBatch) + $(call RunSamevmBatch) # All nio tests jdk_nio: jdk_nio1 jdk_nio2 jdk_nio3 diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/ProblemList.txt Wed Jul 05 17:18:12 2017 +0200 @@ -295,9 +295,6 @@ # jdk_misc -# On Windows com.sun.java.swing.plaf.gtk does not exist, always fails there -com/sun/java/swing/plaf/gtk/Test6635110.java windows-all - # Need to be marked othervm, or changed to be samevm safe com/sun/jndi/ldap/ReadTimeoutTest.java generic-all com/sun/jndi/rmi/registry/RegistryContext/UnbindIdempotent.java generic-all @@ -379,9 +376,6 @@ # Interrupted or IO exception, maybe writing to non-unique named file? com/sun/net/httpserver/bugs/B6373555.java generic-all -# Fails on OpenSolaris, BindException unexpected -java/net/BindException/Test.java generic-all - # Fails on OpenSolaris, times out java/net/MulticastSocket/SetOutgoingIf.java generic-all @@ -507,25 +501,46 @@ ############################################################################ +# jdk_io + +# 6962637 +java/io/File/MaxPathLength.java windows-all + +############################################################################ + # jdk_nio -# Suspect many of these tests auffer from using fixed ports, no concrete -# evidence. +# 6944810 +java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java windows-all + +# 6963118 +java/nio/channels/Selector/Wakeup.java windows-all -# Occasionally Failing with java.lang.AssertionError on Windows X64 -# at sun.nio.ch.PendingIoCache.clearPendingIoMap(PendingIoCache.java:144) -#java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java windows-all +# The asynchronous I/O implementation on Windows requires Windows XP or newer. +# We can remove the following once all Windows 2000 machines have been +# decommissioned. +java/nio/channels/AsynchronousChannelGroup/Basic.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/Identity.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/Restart.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/Unbounded.java windows-5.0 +java/nio/channels/AsynchronousDatagramChannel/Basic.java windows-5.0 +java/nio/channels/AsynchronousFileChannel/Lock.java windows-5.0 +java/nio/channels/AsynchronousServerSocketChannel/Basic.java windows-5.0 +java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/Basic.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/Leaky.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/StressLoopback.java windows-5.0 +java/nio/channels/Channels/Basic2.java windows-5.0 -# Some kind of sleep/wake problem on Windows X64 -java/nio/channels/Selector/Wakeup.java windows-all +# 6959891 +com/sun/nio/sctp/SctpChannel/SocketOptionTests.java # Fails with -ea -esa, Assertion error, but only on Solaris 10 machines? com/sun/nio/sctp/SctpChannel/Send.java generic-all com/sun/nio/sctp/SctpChannel/Shutdown.java generic-all -# Fails on Windows 2000, times out -java/nio/channels/FileChannel/Transfer.java generic-all - # Fails on OpenSolaris, IllegalStateException: Cannot add or remove addresses # from a channel that is bound to the wildcard address com/sun/nio/sctp/SctpChannel/Bind.java generic-all @@ -533,18 +548,6 @@ # Failed on OpenSolaris, java.lang.AssertionError: Unknown event type com/sun/nio/sctp/SctpChannel/Receive.java generic-all -# Triggers a hotspot crash on Fedora 9 32bit -server and Windows X64 samevm -sun/nio/cs/TestUTF8.java generic-all - -# Runtime exception on windows X64, samevm mode -java/nio/channels/Selector/WakeupNow.java generic-all - -# Occasional errors, solarix x86, address already in use, othervm mode -java/nio/channels/Selector/SelectorTest.java generic-all - -# Fails on Linux Fedora 9 X64 -sun/nio/cs/FindDecoderBugs.java generic-all - # Solaris 11 gave assert error and "connection refused", samevm issues? com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java generic-all @@ -555,49 +558,6 @@ com/sun/nio/sctp/SctpMultiChannel/Send.java generic-all com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java generic-all -# Linux 64bit failures. too many files open -java/nio/channels/Selector/HelperSlowToDie.java generic-all - -# Gets java.lang.ExceptionInInitializerError on Windows 2000 (need XP or newer) -java/nio/channels/AsynchronousChannelGroup/Basic.java windows-5.0 -java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java windows-5.0 -java/nio/channels/AsynchronousChannelGroup/Identity.java windows-5.0 -java/nio/channels/AsynchronousChannelGroup/Restart.java windows-5.0 -java/nio/channels/AsynchronousChannelGroup/Unbounded.java windows-5.0 -java/nio/channels/AsynchronousDatagramChannel/Basic.java windows-5.0 -java/nio/channels/AsynchronousFileChannel/Lock.java windows-5.0 -java/nio/channels/AsynchronousServerSocketChannel/Basic.java windows-5.0 -java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java windows-5.0 -java/nio/channels/AsynchronousSocketChannel/Basic.java windows-5.0 -java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java windows-5.0 -java/nio/channels/AsynchronousSocketChannel/Leaky.java windows-5.0 -java/nio/channels/AsynchronousSocketChannel/StressLoopback.java windows-5.0 -java/nio/channels/Channels/Basic2.java windows-5.0 - -# Failed loopback connection? On windows 32bit? -# Considered a stress test, can consume all resources. -java/nio/channels/Selector/LotsOfChannels.java generic-all - -# Windows i586 client, crashed hotspot? Unpredictable -# Considered a stress test, can consume all resources. -java/nio/channels/Selector/RegAfterPreClose.java generic-all - -# Solaris i586, cannot assign address, samevm issues -java/nio/channels/Selector/SelectorLimit.java generic-all - -# Socket timeout windows X64 -java/nio/channels/ServerSocketChannel/AdaptServerSocket.java windows-all - -# Timeouts etc. on Window -java/nio/channels/SocketChannel/ConnectState.java windows-all -java/nio/channels/SocketChannel/FinishConnect.java windows-all - -# Fails on all platforms due to overlap of JDK jar file contents: -sun/nio/cs/Test4200310.sh generic-all - -# Depends on motif packages that do not exist all the time: -sun/nio/cs/TestX11CNS.java generic-all - ############################################################################ # jdk_rmi @@ -848,9 +808,6 @@ # jdk_swing (not using samevm) -# Fails on solaris 10 sparc, throws RuntimeException that just says "failed" -javax/swing/JLabel/6501991/bug6501991.java generic-all - # Fails on solaris 11 i586, with othervm javax/swing/JFileChooser/6570445/bug6570445.java generic-all javax/swing/JFileChooser/6738668/bug6738668.java generic-all diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/com/sun/java/swing/plaf/gtk/Test6635110.java --- a/jdk/test/com/sun/java/swing/plaf/gtk/Test6635110.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/com/sun/java/swing/plaf/gtk/Test6635110.java Wed Jul 05 17:18:12 2017 +0200 @@ -28,7 +28,6 @@ @run main Test6635110 */ -import com.sun.java.swing.plaf.gtk.GTKLookAndFeel; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; @@ -59,7 +58,12 @@ } public static void main(String[] args) throws Exception { - UIManager.setLookAndFeel(new GTKLookAndFeel()); + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + } catch (Exception e) { + System.out.println("GTKLookAndFeel cannot be set, skipping this test"); + return; + } SwingUtilities.invokeAndWait(new Test6635110()); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/com/sun/java/swing/plaf/gtk/Test6963870.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/com/sun/java/swing/plaf/gtk/Test6963870.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6963870 + @summary Tests that GTKPainter.ListTableFocusBorder.getBorderInsets() + doesn't return null + @author Peter Zhelezniakov + @run main Test6963870 +*/ + +import java.awt.Insets; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.Border; + +public class Test6963870 implements Runnable { + + final static String[] UI_NAMES = { + "List.focusCellHighlightBorder", + "List.focusSelectedCellHighlightBorder", + "List.noFocusBorder", + "Table.focusCellHighlightBorder", + "Table.focusSelectedCellHighlightBorder", + }; + + public void run() { + for (String uiName: UI_NAMES) { + test(uiName); + } + } + + void test(String uiName) { + Border b = UIManager.getBorder(uiName); + Insets i = b.getBorderInsets(null); + if (i == null) { + throw new RuntimeException("getBorderInsets() returns null for " + uiName); + } + } + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + } catch (Exception e) { + System.out.println("GTKLookAndFeel cannot be set, skipping this test"); + return; + } + + SwingUtilities.invokeAndWait(new Test6963870()); + } +} + diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java --- a/jdk/test/java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + /* @test @bug 6304473 6727884 diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java --- a/jdk/test/java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java Wed Jul 05 17:18:12 2017 +0200 @@ -34,35 +34,40 @@ import java.awt.*; import java.awt.event.*; -import java.lang.Math; + +import sun.awt.SunToolkit; + import test.java.awt.regtesthelpers.Util; public class LoopRobustness { - static int clicks = 0; + final static long TIMEOUT = 5000; final static Object LOCK = new Object(); - static volatile boolean notifyOccur = false; - public static void main(String [] args) { + public static int clicks = 0; + public static volatile boolean notifyOccured = false; + public static volatile boolean otherExceptionsCaught = false; + + public static void main(String [] args) throws Exception { ThreadGroup mainThreadGroup = Thread.currentThread().getThreadGroup(); long at; //wait for a TIMEOUT giving a chance to a new Thread above to accomplish its stuff. - synchronized (LoopRobustness.LOCK){ + synchronized (LoopRobustness.LOCK) { new Thread(new TestThreadGroup(mainThreadGroup, "TestGroup"), new Impl()).start(); at = System.currentTimeMillis(); try { - while(!notifyOccur && System.currentTimeMillis() - at < TIMEOUT) { + while (!notifyOccured && (System.currentTimeMillis() - at < TIMEOUT)) { LoopRobustness.LOCK.wait(1000); } - } catch(InterruptedException e){ + } catch (InterruptedException e) { throw new RuntimeException("Test interrupted.", e); } } - if( !notifyOccur){ + if (!notifyOccured) { //notify doesn't occur after a reasonable time. - throw new RuntimeException("Test failed. Second Thread didn't notify MainThread."); + throw new RuntimeException("Test FAILED: second thread hasn't notified MainThread"); } //now wait for two clicks @@ -75,7 +80,10 @@ } } if (clicks != 2) { - throw new RuntimeException("robot should press button twice"); + throw new RuntimeException("Test FAILED: robot should press button twice"); + } + if (otherExceptionsCaught) { + throw new RuntimeException("Test FAILED: unexpected exceptions caught"); } } } @@ -83,18 +91,11 @@ class Impl implements Runnable{ static Robot robot; public void run() { + SunToolkit.createNewAppContext(); + Button b = new Button("Press me to test the AWT-Event Queue thread"); Frame lr = new Frame("ROBUST FRAME"); - /* Must load Toolkit on this thread only, rather then on Main. - If load on Main (on the parent ThreadGroup of current ThreadGroup) then - EDT will be created on Main thread and supplied with it's own exceptionHandler, - which just throws an Exception and terminates current thread. - The test implies that EDT is created on the child ThreadGroup (testThreadGroup) - which is supplied with its own uncaughtException(). - */ - Toolkit.getDefaultToolkit(); lr.setBounds(100, 100, 300, 100); - b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { LoopRobustness.clicks++; @@ -107,40 +108,46 @@ try { robot = new Robot(); - } catch(AWTException e){ + } catch (AWTException e) { throw new RuntimeException("Test interrupted.", e); } Util.waitForIdle(robot); synchronized (LoopRobustness.LOCK){ LoopRobustness.LOCK.notify(); - LoopRobustness.notifyOccur = true; + LoopRobustness.notifyOccured = true; } int i = 0; - while(i < 2){ + while (i < 2) { robot.mouseMove(b.getLocationOnScreen().x + b.getWidth()/2, - b.getLocationOnScreen().y + b.getHeight()/2 ); + b.getLocationOnScreen().y + b.getHeight()/2); + Util.waitForIdle(robot); robot.mousePress(InputEvent.BUTTON1_MASK); - // robot.delay(10); + Util.waitForIdle(robot); robot.mouseRelease(InputEvent.BUTTON1_MASK); + Util.waitForIdle(robot); i++; - robot.delay(1000); } } } class TestThreadGroup extends ThreadGroup { - TestThreadGroup(ThreadGroup threadGroup, String name){ + TestThreadGroup(ThreadGroup threadGroup, String name) { super(threadGroup, name); } - public void uncaughtException(Thread exitedThread, Throwable e) { - e.printStackTrace(); - if ((e instanceof ExceptionInInitializerError) || (e instanceof - NoClassDefFoundError)){ - throw new RuntimeException("Test failed: other Exceptions were thrown ", e); + public void uncaughtException(Thread thread, Throwable e) { + System.out.println("Exception caught: " + e); + e.printStackTrace(System.out); + System.out.flush(); + if ((e instanceof ExceptionInInitializerError) || + (e instanceof NoClassDefFoundError)) + { + // These two are expected + return; } + LoopRobustness.otherExceptionsCaught = true; } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/awt/EventDispatchThread/PreserveDispathThread/PreserveDispatchThread.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/EventDispatchThread/PreserveDispathThread/PreserveDispatchThread.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 6424157 + @author Artem Ananiev: area=eventqueue + @run main PreserveDispatchThread +*/ + +import java.awt.*; +import java.awt.event.*; + +public class PreserveDispatchThread { + + private static volatile Frame f; + private static volatile Dialog d; + + private static volatile boolean isEDT = true; + + public static void main(String[] args) throws Exception { + f = new Frame("F"); + f.setSize(320, 340); + f.setLocationRelativeTo(null); + f.setVisible(true); + + try { + test1(); + if (!isEDT) { + throw new RuntimeException("Test FAILED (test1): event dispatch thread is changed"); + } + + test2(); + if (!isEDT) { + throw new RuntimeException("Test FAILED (test2): event dispatch thread is changed"); + } + + test3(); + if (!isEDT) { + throw new RuntimeException("Test FAILED (test3): event dispatch thread is changed"); + } + } finally { + if (d != null) { + d.dispose(); + } + f.dispose(); + } + } + + /* + * Tests that push/pop doesn't change the dispatch thread if + * called on EDT. + */ + private static void test1() throws Exception { + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + TestEventQueue teq = new TestEventQueue(); + EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + try { + seq.push(teq); + d = new TestDialog(); + d.setVisible(true); + checkEDT(); + } finally { + teq.pop(); + } + checkEDT(); + } + }); + } + + /* + * Tests that push/pop doesn't change the dispatch thread if + * called on the main thread. + */ + private static void test2() throws Exception { + TestEventQueue teq = new TestEventQueue(); + EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + try { + seq.push(teq); + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + checkEDT(); + d = new TestDialog(); + d.setVisible(true); + checkEDT(); + } + }); + } finally { + teq.pop(); + } + } + + private static final Object test3Lock = new Object(); + private static boolean test3Sync = false; + + /* + * A complex test: several nested invokeLater() are called and + * in every runnable a check for EDT is performed. At the ent + * of the test we wait for all the runnables to be processed + * and the dialog is disposed; otherwise the last EDT check can + * be later than this method returns and the whole test is passed. + */ + private static void test3() throws Exception { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + d = new Dialog(f, true); + d.setSize(240, 180); + d.setLocationRelativeTo(f); + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + d.setVisible(true); + checkEDT(); + } + }); + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + TestEventQueue teq = new TestEventQueue(); + EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + try { + seq.push(teq); + checkEDT(); + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + d.dispose(); + checkEDT(); + synchronized (test3Lock) { + test3Sync = true; + test3Lock.notify(); + } + } + }); + } finally { + teq.pop(); + } + checkEDT(); + } + }); + checkEDT(); + } + }); + synchronized (test3Lock) { + while (!test3Sync) { + try { + test3Lock.wait(); + } catch (InterruptedException ie) { + break; + } + } + } + // Make sure all the nested invokeLater/invokeAndWait are processed + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + } + }); + } + + private static void checkEDT() { + isEDT = isEDT && EventQueue.isDispatchThread(); + } + + private static class TestEventQueue extends EventQueue { + public TestEventQueue() { + super(); + } + public void pop() { + super.pop(); + } + } + + private static class TestDialog extends Dialog { + private volatile boolean dialogShown = false; + private volatile boolean paintCalled = false; + public TestDialog() { + super(f, true); + setSize(240, 180); + setLocationRelativeTo(f); + addComponentListener(new ComponentAdapter() { + @Override + public void componentShown(ComponentEvent e) { + if (paintCalled) { + dispose(); + } + dialogShown = true; + } + }); + } + @Override + public void paint(Graphics g) { + if (dialogShown) { + dispose(); + } + paintCalled = true; + } + } + +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/awt/EventQueue/PushPopDeadlock2/PushPopTest.java --- a/jdk/test/java/awt/EventQueue/PushPopDeadlock2/PushPopTest.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/awt/EventQueue/PushPopDeadlock2/PushPopTest.java Wed Jul 05 17:18:12 2017 +0200 @@ -43,6 +43,7 @@ Runnable dummy = new Runnable() { public void run() { System.err.println("Dummy is here."); + System.err.flush(); } }; EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue(); @@ -58,10 +59,11 @@ Runnable runnable = new Runnable() { public void run() { System.err.println("Dummy from SunToolkit"); + System.err.flush(); } }; InvocationEvent ie = new InvocationEvent(eq2, runnable, null, false); - System.err.println(ie); +// System.err.println(ie); SunToolkit.postEvent(SunToolkit.targetToAppContext(frame), ie); eq1.pop(); frame.dispose(); @@ -70,14 +72,14 @@ class MyEventQueue1 extends EventQueue { - public void pop() throws EmptyStackException { + public void pop() { super.pop(); } } class MyEventQueue2 extends EventQueue { - protected void pop() throws EmptyStackException { + protected void pop() { System.err.println("pop2()"); Thread.dumpStack(); try { @@ -85,7 +87,8 @@ public void run() { Runnable runnable = new Runnable() { public void run() { - System.err.println("Dummy from here"); + System.err.println("Dummy from pop"); + System.err.flush(); } }; InvocationEvent ie = new InvocationEvent(MyEventQueue2.this, runnable, null, false); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/awt/FontClass/FontPrivilege.java --- a/jdk/test/java/awt/FontClass/FontPrivilege.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/awt/FontClass/FontPrivilege.java Wed Jul 05 17:18:12 2017 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 5010310 6319835 6904882 + * @bug 5010310 6319835 6904882 6968373 * @summary test fonts can be created in the presence of a security manager * @run main/othervm/secure=java.lang.SecurityManager FontPrivilege */ diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/beans/Introspector/Test6707234.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/beans/Introspector/Test6707234.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6707234 + * @summary Tests setter in a complex bean + * @author Sergey Malenkov + */ + +public class Test6707234 { + public static void main(String[] args) { + if (null == BeanUtils.getPropertyDescriptor(C.class, "number").getWriteMethod()) { + throw new Error("no write method"); + } + } + + public interface I { + void setNumber(Object number); + Number getNumber(); + } + + public class C implements I { + public void setNumber(Object value) { + } + public void setNumber(Long value) { + } + public Long getNumber() { + return null; + } + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/beans/Introspector/Test6963811.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/beans/Introspector/Test6963811.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6963811 + * @summary Tests deadlock in Introspector + * @author Sergey Malenkov + */ + +import java.beans.Introspector; +import java.beans.SimpleBeanInfo; + +public class Test6963811 implements Runnable { + private final long time; + private final boolean sync; + + public Test6963811(long time, boolean sync) { + this.time = time; + this.sync = sync; + } + + public void run() { + try { + Thread.sleep(this.time); // increase the chance of the deadlock + Introspector.getBeanInfo( + this.sync ? Super.class : Sub.class, + this.sync ? null : Object.class); + } + catch (Exception exception) { + exception.printStackTrace(); + } + } + + public static void main(String[] args) throws Exception { + Thread[] threads = new Thread[2]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new Thread(new Test6963811(0L, i > 0)); + threads[i].start(); + Thread.sleep(500L); // increase the chance of the deadlock + } + for (Thread thread : threads) { + thread.join(); + } + } + + public static class Super { + } + + public static class Sub extends Super { + } + + public static class SubBeanInfo extends SimpleBeanInfo { + public SubBeanInfo() { + new Test6963811(1000L, true).run(); + } + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/beans/PropertyEditor/Test6963811.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/beans/PropertyEditor/Test6963811.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6963811 + * @summary Tests deadlock in PropertyEditorManager + * @author Sergey Malenkov + */ + +import java.beans.PropertyEditorManager; +import sun.beans.editors.StringEditor; + +public class Test6963811 implements Runnable { + private final long time; + private final boolean sync; + + public Test6963811(long time, boolean sync) { + this.time = time; + this.sync = sync; + } + + public void run() { + try { + Thread.sleep(this.time); // increase the chance of the deadlock + if (this.sync) { + synchronized (Test6963811.class) { + PropertyEditorManager.findEditor(Super.class); + } + } + else { + PropertyEditorManager.findEditor(Sub.class); + } + } + catch (Exception exception) { + exception.printStackTrace(); + } + } + + public static void main(String[] args) throws Exception { + Thread[] threads = new Thread[2]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new Thread(new Test6963811(0L, i > 0)); + threads[i].start(); + Thread.sleep(500L); // increase the chance of the deadlock + } + for (Thread thread : threads) { + thread.join(); + } + } + + public static class Super { + } + + public static class Sub extends Super { + } + + public static class SubEditor extends StringEditor { + public SubEditor() { + new Test6963811(1000L, true).run(); + } + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/beans/XMLEncoder/Test6963811.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/beans/XMLEncoder/Test6963811.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6963811 + * @summary Tests deadlock in Encoder + * @author Sergey Malenkov + */ + +import java.beans.Encoder; +import java.beans.DefaultPersistenceDelegate; + +public class Test6963811 implements Runnable { + private static final Encoder ENCODER = new Encoder(); + private final long time; + private final boolean sync; + + public Test6963811(long time, boolean sync) { + this.time = time; + this.sync = sync; + } + + public void run() { + try { + Thread.sleep(this.time); // increase the chance of the deadlock + if (this.sync) { + synchronized (Test6963811.class) { + ENCODER.getPersistenceDelegate(Super.class); + } + } + else { + ENCODER.getPersistenceDelegate(Sub.class); + } + } + catch (Exception exception) { + exception.printStackTrace(); + } + } + + public static void main(String[] args) throws Exception { + Thread[] threads = new Thread[2]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new Thread(new Test6963811(0L, i > 0)); + threads[i].start(); + Thread.sleep(500L); // increase the chance of the deadlock + } + for (Thread thread : threads) { + thread.join(); + } + } + + public static class Super { + } + + public static class Sub extends Super { + } + + public static class SubPersistenceDelegate extends DefaultPersistenceDelegate { + public SubPersistenceDelegate() { + new Test6963811(1000L, true).run(); + } + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/lang/String/Supplementary.java --- a/jdk/test/java/lang/String/Supplementary.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/lang/String/Supplementary.java Wed Jul 05 17:18:12 2017 +0200 @@ -62,7 +62,7 @@ 0 1 2345 678 9 012 345678 9 01 2 */ "\uD800\uDC00!#$\uD800%&\uD800\uDC00;+\uDC00<>;=^\uDC00\\@\uD800\uDC00", - // includes an undefined supprementary characters in Unicode 4.0.0 + // includes an undefined supplementary character in Unicode 4.0.0 /* 1 11 1 1111 1 0 1 2345 6 789 0 12 3 4567 8 */ "\uDB40\uDE00abc\uDE01\uDB40de\uDB40\uDE02f\uDB40\uDE03ghi\uDB40\uDE02", @@ -168,7 +168,7 @@ * string in input[m]. * * The meaning of each element in golden3[][n] - * golden3[][0]: characater which is searched. + * golden3[][0]: character which is searched. * golden3[][2]: the golden data for indexOf(int ch) * From golden3[][2] to golden3[][n-1]: * the golden data for indexOf(int ch, int fromIndex) @@ -201,17 +201,17 @@ /* * Normal case */ - testIndexOf(First, s, golden3[i][0], golden3[i][2]); + testIndexOf(s, golden3[i][0], golden3[i][2]); /* * Abnormal case - char which isn't included in the string. */ - testIndexOf(First, s, 'Z', -1); - testIndexOf(First, s, 0xDB98, -1); - testIndexOf(First, s, 0xDE76, -1); - testIndexOf(First, s, 0x12345, -1); - testIndexOf(First, s, -1, -1); - testIndexOf(First, s, 0x110000, -1); + testIndexOf(s, 'Z', -1); + testIndexOf(s, 0xDB98, -1); + testIndexOf(s, 0xDE76, -1); + testIndexOf(s, 0x12345, -1); + testIndexOf(s, -1, -1); + testIndexOf(s, 0x110000, -1); } } @@ -229,7 +229,7 @@ */ int fromIndex = 0; for (int j = 2; j < golden3[i].length; j++) { - fromIndex = testIndexOf(First, s, fromIndex, ch, + fromIndex = testIndexOf(s, fromIndex, ch, golden3[i][j]) + 1; } @@ -237,19 +237,19 @@ * Abnormal case1 - char is included in the string but fromIndex * is incorrect. */ - testIndexOf(First, s, -1, ch, golden3[i][2]); - testIndexOf(First, s, s.length(), ch, + testIndexOf(s, -1, ch, golden3[i][2]); + testIndexOf(s, s.length(), ch, golden3[i][golden3[i].length-1]); /* * Abnormal case2 - char which isn't included in the string. */ - testIndexOf(First, s, 0, 'Z', -1); - testIndexOf(First, s, 0, 0xDB98, -1); - testIndexOf(First, s, 0, 0xDE76, -1); - testIndexOf(First, s, 0, 0x12345, -1); - testIndexOf(First, s, 0, -1, -1); - testIndexOf(First, s, 0, 0x110000, -1); + testIndexOf(s, 0, 'Z', -1); + testIndexOf(s, 0, 0xDB98, -1); + testIndexOf(s, 0, 0xDE76, -1); + testIndexOf(s, 0, 0x12345, -1); + testIndexOf(s, 0, -1, -1); + testIndexOf(s, 0, 0x110000, -1); } } @@ -264,18 +264,18 @@ /* * Normal case */ - testIndexOf(Last, s, golden3[i][0], + testLastIndexOf(s, golden3[i][0], golden3[i][golden3[i].length-2]); /* * Abnormal case - char which isn't included in the string. */ - testIndexOf(Last, s, 'Z', -1); - testIndexOf(Last, s, 0xDB98, -1); - testIndexOf(Last, s, 0xDE76, -1); - testIndexOf(Last, s, 0x12345, -1); - testIndexOf(Last, s, -1, -1); - testIndexOf(Last, s, 0x110000, -1); + testLastIndexOf(s, 'Z', -1); + testLastIndexOf(s, 0xDB98, -1); + testLastIndexOf(s, 0xDE76, -1); + testLastIndexOf(s, 0x12345, -1); + testLastIndexOf(s, -1, -1); + testLastIndexOf(s, 0x110000, -1); } } @@ -294,7 +294,7 @@ */ int fromIndex = len - 1; for (int j = golden3[i].length - 2; j > 0; j--) { - fromIndex = testIndexOf(Last, s, fromIndex, ch, + fromIndex = testLastIndexOf(s, fromIndex, ch, golden3[i][j]) - 1; } @@ -302,18 +302,18 @@ * Abnormal case1 - char is included in the string but fromIndex * is incorrect. */ - testIndexOf(Last, s, -1, ch, golden3[i][1]); - testIndexOf(Last, s, len, ch, golden3[i][golden3[i].length-2]); + testLastIndexOf(s, -1, ch, golden3[i][1]); + testLastIndexOf(s, len, ch, golden3[i][golden3[i].length-2]); /* * Abnormal case2 - char which isn't included in the string. */ - testIndexOf(Last, s, len, 'Z', -1); - testIndexOf(Last, s, len, 0xDB98, -1); - testIndexOf(Last, s, len, 0xDE76, -1); - testIndexOf(Last, s, len, 0x12345, -1); - testIndexOf(Last, s, len, -1, -1); - testIndexOf(Last, s, len, 0x110000, -1); + testLastIndexOf(s, len, 'Z', -1); + testLastIndexOf(s, len, 0xDB98, -1); + testLastIndexOf(s, len, 0xDE76, -1); + testLastIndexOf(s, len, 0x12345, -1); + testLastIndexOf(s, len, -1, -1); + testLastIndexOf(s, len, 0x110000, -1); } } @@ -471,7 +471,7 @@ result, expected); result = str.offsetByCodePoints(j, -nCodePoints); check(result != 0, - "offsetBycodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")", + "offsetByCodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")", result, 0); } @@ -531,7 +531,7 @@ result, expected); result = str.offsetByCodePoints(j, -nCodePoints); check(result != 0, - "offsetBycodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")", + "offsetByCodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")", result, 0); } } @@ -539,7 +539,7 @@ static final boolean At = true, Before = false; - static final boolean First = true, Last = false; + static final boolean FIRST = true, LAST = false; static void testCodePoint(boolean isAt, String s, int index, int expected) { int c = isAt ? s.codePointAt(index) : s.codePointBefore(index); @@ -563,22 +563,72 @@ + s + "> should throw StringIndexOutOfBoundsPointerException."); } - static void testIndexOf(boolean isFirst, String s, int c, int expected) { - int index = isFirst ? s.indexOf(c) : s.lastIndexOf(c); + static void testIndexOf(String s, int c, int expected) { + testIndexOf2(s, c, expected); + if (s.indexOf(c) != -1) { + testIndexOf2(s + (char) c, c, expected); + if (Character.isSupplementaryCodePoint(c)) { + char[] surrogates = Character.toChars(c); + testIndexOf2(s + new String(surrogates), c, expected); + testIndexOf2(s + surrogates[0], c, expected); + testIndexOf2(s + surrogates[1], c, expected); + testIndexOf2(new String(surrogates) + s, c, 0); + testIndexOf2(surrogates[0] + s, c, expected + 1); + testIndexOf2(surrogates[1] + s, c, expected + 1); + } + } + } + + static void testIndexOf2(String s, int c, int expected) { + int index = s.indexOf(c); check(index != expected, - (isFirst ? "i" : "lastI") + "ndexOf(" + toHexString(c) - + ") for <" + s + ">", index, expected); + "indexOf(" + toHexString(c) + ") for <" + s + ">", + index, expected); } - static int testIndexOf(boolean isFirst, String s, int fromIndex, int c, - int expected) { - int index = isFirst ? s.indexOf(c, fromIndex) : - s.lastIndexOf(c, fromIndex); + static void testLastIndexOf(String s, int c, int expected) { + testLastIndexOf2(s, c, expected); + if (s.lastIndexOf(c) != -1) { + testLastIndexOf2((char) c + s, c, expected + 1); + if (Character.isSupplementaryCodePoint(c)) { + char[] surrogates = Character.toChars(c); + testLastIndexOf2(s + new String(surrogates), c, s.length()); + testLastIndexOf2(s + surrogates[0], c, expected); + testLastIndexOf2(s + surrogates[1], c, expected); + testLastIndexOf2(new String(surrogates) + s, c, expected + 2); + testLastIndexOf2(surrogates[0] + s, c, expected + 1); + testLastIndexOf2(surrogates[1] + s, c, expected + 1); + } + } + } + + static void testLastIndexOf2(String s, int c, int expected) { + int index = s.lastIndexOf(c); check(index != expected, - (isFirst ? "i" : "lastI") + "ndexOf(" + toHexString(c) + ", " - + fromIndex + ") for <" + s + ">", index, expected); + "lastIndexOf(" + toHexString(c) + ") for <" + s + ">", + index, expected); + } + + static int testIndexOf(String s, int fromIndex, int c, int expected) { + int index = s.indexOf(c, fromIndex); + + check(index != expected, + "indexOf(" + toHexString(c) + ", " + + fromIndex + ") for <" + s + ">", + index, expected); + + return index; + } + + static int testLastIndexOf(String s, int fromIndex, int c, int expected) { + int index = s.lastIndexOf(c, fromIndex); + + check(index != expected, + "lastIndexOf(" + toHexString(c) + ", " + + fromIndex + ") for <" + s + ">", + index, expected); return index; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/lang/StringBuffer/Supplementary.java --- a/jdk/test/java/lang/StringBuffer/Supplementary.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/lang/StringBuffer/Supplementary.java Wed Jul 05 17:18:12 2017 +0200 @@ -24,7 +24,7 @@ /* * * @test - * @bug 4533872 4915683 4985217 5017280 + * @bug 4533872 4915683 4985217 5017280 6937112 * @summary Unit tests for supplementary character support (JSR-204) */ @@ -57,7 +57,7 @@ 0 1 2345 678 9 012 345678 9 01 2 */ "\uD800\uDC00!#$\uD800%&\uD800\uDC00;+\uDC00<>;=^\uDC00\\@\uD800\uDC00", - // includes an undefined supprementary characters in Unicode 4.0.0 + // includes an undefined supplementary character in Unicode 4.0.0 /* 1 11 1 1111 1 0 1 2345 6 789 0 12 3 4567 8 */ "\uDB40\uDE00abc\uDE01\uDB40de\uDB40\uDE02f\uDB40\uDE03ghi\uDB40\uDE02", @@ -151,7 +151,7 @@ "\uD800on\uDC00ml\uDC00\uDC00ki9\uD800\uDC00hgfe\uDBFF\uDFFFdcba\uDC00", "\uD800\uDC00@\\\uDC00^=;><\uDC00+;\uD800\uDC00&%\uD800$#!\uD800\uDC00", - // includes an undefined supprementary characters in Unicode 4.0.0 + // includes an undefined supplementary character in Unicode 4.0.0 "\uDB40\uDE02ihg\uDB40\uDE03f\uDB40\uDE02ed\uDB40\uDE01cba\uDB40\uDE00", }; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/lang/StringBuilder/Supplementary.java --- a/jdk/test/java/lang/StringBuilder/Supplementary.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/lang/StringBuilder/Supplementary.java Wed Jul 05 17:18:12 2017 +0200 @@ -57,7 +57,7 @@ 0 1 2345 678 9 012 345678 9 01 2 */ "\uD800\uDC00!#$\uD800%&\uD800\uDC00;+\uDC00<>;=^\uDC00\\@\uD800\uDC00", - // includes an undefined supprementary characters in Unicode 4.0.0 + // includes an undefined supplementary character in Unicode 4.0.0 /* 1 11 1 1111 1 0 1 2345 6 789 0 12 3 4567 8 */ "\uDB40\uDE00abc\uDE01\uDB40de\uDB40\uDE02f\uDB40\uDE03ghi\uDB40\uDE02", @@ -151,7 +151,7 @@ "\uD800on\uDC00ml\uDC00\uDC00ki9\uD800\uDC00hgfe\uDBFF\uDFFFdcba\uDC00", "\uD800\uDC00@\\\uDC00^=;><\uDC00+;\uD800\uDC00&%\uD800$#!\uD800\uDC00", - // includes an undefined supprementary characters in Unicode 4.0.0 + // includes an undefined supplementary character in Unicode 4.0.0 "\uDB40\uDE02ihg\uDB40\uDE03f\uDB40\uDE02ed\uDB40\uDE01cba\uDB40\uDE00", }; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/lang/Throwable/SuppressedExceptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/Throwable/SuppressedExceptions.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.*; +import java.util.*; + +/* + * @test + * @bug 6911258 6962571 + * @summary Basic tests of suppressed exceptions + * @author Joseph D. Darcy + */ + +public class SuppressedExceptions { + private static String message = "Bad suppressed exception information"; + + public static void main(String... args) throws Exception { + basicSupressionTest(); + serializationTest(); + selfReference(); + } + + private static void basicSupressionTest() { + Throwable throwable = new Throwable(); + RuntimeException suppressed = new RuntimeException("A suppressed exception."); + AssertionError repressed = new AssertionError("A repressed error."); + + Throwable[] t0 = throwable.getSuppressedExceptions(); + if (t0.length != 0) { + throw new RuntimeException(message); + } + throwable.printStackTrace(); + + throwable.addSuppressedException(suppressed); + Throwable[] t1 = throwable.getSuppressedExceptions(); + if (t1.length != 1 || + t1[0] != suppressed) {throw new RuntimeException(message); + } + throwable.printStackTrace(); + + throwable.addSuppressedException(repressed); + Throwable[] t2 = throwable.getSuppressedExceptions(); + if (t2.length != 2 || + t2[0] != suppressed || + t2[1] != repressed) { + throw new RuntimeException(message); + } + throwable.printStackTrace(); + } + + private static void serializationTest() throws Exception { + /* + * Bytes of the serial form of + * + * (new Throwable())setStackTrace(new StackTraceElement[0]) + * + * from JDK 6; suppressedException field will be missing and + * thus default to null upon deserialization. + */ + byte[] bytes = { + (byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13, + (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, + (byte)0x67, (byte)0x2e, (byte)0x54, (byte)0x68, (byte)0x72, (byte)0x6f, (byte)0x77, (byte)0x61, + (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0xd5, (byte)0xc6, (byte)0x35, (byte)0x27, (byte)0x39, + (byte)0x77, (byte)0xb8, (byte)0xcb, (byte)0x03, (byte)0x00, (byte)0x03, (byte)0x4c, (byte)0x00, + (byte)0x05, (byte)0x63, (byte)0x61, (byte)0x75, (byte)0x73, (byte)0x65, (byte)0x74, (byte)0x00, + (byte)0x15, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, + (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x54, (byte)0x68, (byte)0x72, (byte)0x6f, + (byte)0x77, (byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0x3b, (byte)0x4c, (byte)0x00, + (byte)0x0d, (byte)0x64, (byte)0x65, (byte)0x74, (byte)0x61, (byte)0x69, (byte)0x6c, (byte)0x4d, + (byte)0x65, (byte)0x73, (byte)0x73, (byte)0x61, (byte)0x67, (byte)0x65, (byte)0x74, (byte)0x00, + (byte)0x12, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, + (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x72, (byte)0x69, + (byte)0x6e, (byte)0x67, (byte)0x3b, (byte)0x5b, (byte)0x00, (byte)0x0a, (byte)0x73, (byte)0x74, + (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65, + (byte)0x74, (byte)0x00, (byte)0x1e, (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, + (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, + (byte)0x74, (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, + (byte)0x65, (byte)0x45, (byte)0x6c, (byte)0x65, (byte)0x6d, (byte)0x65, (byte)0x6e, (byte)0x74, + (byte)0x3b, (byte)0x78, (byte)0x70, (byte)0x71, (byte)0x00, (byte)0x7e, (byte)0x00, (byte)0x04, + (byte)0x70, (byte)0x75, (byte)0x72, (byte)0x00, (byte)0x1e, (byte)0x5b, (byte)0x4c, (byte)0x6a, + (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, + (byte)0x2e, (byte)0x53, (byte)0x74, (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, + (byte)0x61, (byte)0x63, (byte)0x65, (byte)0x45, (byte)0x6c, (byte)0x65, (byte)0x6d, (byte)0x65, + (byte)0x6e, (byte)0x74, (byte)0x3b, (byte)0x02, (byte)0x46, (byte)0x2a, (byte)0x3c, (byte)0x3c, + (byte)0xfd, (byte)0x22, (byte)0x39, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0xac, (byte)0xed, (byte)0x00, + (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13, (byte)0x6a, (byte)0x61, (byte)0x76, + (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x54, + (byte)0x68, (byte)0x72, (byte)0x6f, (byte)0x77, (byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65, + (byte)0xd5, (byte)0xc6, (byte)0x35, (byte)0x27, (byte)0x39, (byte)0x77, (byte)0xb8, (byte)0xcb, + (byte)0x03, (byte)0x00, (byte)0x03, (byte)0x4c, (byte)0x00, (byte)0x05, (byte)0x63, (byte)0x61, + (byte)0x75, (byte)0x73, (byte)0x65, (byte)0x74, (byte)0x00, (byte)0x15, (byte)0x4c, (byte)0x6a, + (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, + (byte)0x2f, (byte)0x54, (byte)0x68, (byte)0x72, (byte)0x6f, (byte)0x77, (byte)0x61, (byte)0x62, + (byte)0x6c, (byte)0x65, (byte)0x3b, (byte)0x4c, (byte)0x00, (byte)0x0d, (byte)0x64, (byte)0x65, + (byte)0x74, (byte)0x61, (byte)0x69, (byte)0x6c, (byte)0x4d, (byte)0x65, (byte)0x73, (byte)0x73, + (byte)0x61, (byte)0x67, (byte)0x65, (byte)0x74, (byte)0x00, (byte)0x12, (byte)0x4c, (byte)0x6a, + (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x6e, (byte)0x67, (byte)0x3b, + (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x72, (byte)0x69, + (byte)0x5b, (byte)0x00, (byte)0x0a, (byte)0x73, (byte)0x74, (byte)0x61, (byte)0x63, (byte)0x6b, + (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65, (byte)0x74, (byte)0x00, (byte)0x1e, + (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, + (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x61, (byte)0x63, + (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65, (byte)0x45, (byte)0x6c, + (byte)0x65, (byte)0x6d, (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x3b, (byte)0x78, (byte)0x70, + (byte)0x71, (byte)0x00, (byte)0x7e, (byte)0x00, (byte)0x04, (byte)0x70, (byte)0x75, (byte)0x72, + (byte)0x00, (byte)0x1e, (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, + (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x53, (byte)0x74, + (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65, + (byte)0x45, (byte)0x6c, (byte)0x65, (byte)0x6d, (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x3b, + (byte)0x02, (byte)0x46, (byte)0x2a, (byte)0x3c, (byte)0x3c, (byte)0xfd, (byte)0x22, (byte)0x39, + (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, + }; + + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(bais); + + Object o = ois.readObject(); + Throwable throwable = (Throwable) o; + + System.err.println("TESTING SERIALIZED EXCEPTION"); + + Throwable[] t0 = throwable.getSuppressedExceptions(); + if (t0.length != 0) { // Will fail if t0 is null. + throw new RuntimeException(message); + } + throwable.printStackTrace(); + } + + private static void selfReference() { + Throwable throwable1 = new RuntimeException(); + Throwable throwable2 = new AssertionError(); + throwable1.initCause(throwable2); + throwable2.initCause(throwable1); + + throwable1.printStackTrace(); + + + throwable1.addSuppressedException(throwable1); + throwable1.addSuppressedException(throwable2); + + throwable1.printStackTrace(); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/net/Authenticator/B4769350.java --- a/jdk/test/java/net/Authenticator/B4769350.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/net/Authenticator/B4769350.java Wed Jul 05 17:18:12 2017 +0200 @@ -54,6 +54,7 @@ boolean allowerror; Client (String authority, String path, boolean allowerror) { + super("Thread-" + path); this.authority = authority; this.path = path; this.allowerror = allowerror; @@ -72,7 +73,8 @@ error = true; } catch (IOException e) { if (!allowerror) { - System.out.println (e); + System.out.println (Thread.currentThread().getName() + " " + e); + e.printStackTrace(); error = true; } } @@ -94,6 +96,7 @@ } void okReply (HttpTransaction req) throws IOException { + req.addResponseHeader ("Connection", "close"); req.setResponseEntityBody ("Hello ."); req.sendResponse (200, "Ok"); req.orderlyClose(); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/net/BindException/Test.java --- a/jdk/test/java/net/BindException/Test.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/net/BindException/Test.java Wed Jul 05 17:18:12 2017 +0200 @@ -180,7 +180,7 @@ while (addrs.hasMoreElements()) { InetAddress ia = (InetAddress)addrs.nextElement(); - if (ia.isLoopbackAddress()) { + if (ia.isLoopbackAddress() || ia.isAnyLocalAddress()) { continue; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/net/Inet6Address/B6214234.java --- a/jdk/test/java/net/Inet6Address/B6214234.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/net/Inet6Address/B6214234.java Wed Jul 05 17:18:12 2017 +0200 @@ -23,7 +23,7 @@ /** * @test - * @bug 6214234 + * @bug 6214234 6967937 * @summary IPv6 scope_id for local addresses not set in Solaris 10 */ @@ -51,6 +51,7 @@ return; } if (addr.getScopeId() == 0) { + System.out.println("addr: "+ addr); throw new RuntimeException ("Non zero scope_id expected"); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/net/ipv6tests/Tests.java --- a/jdk/test/java/net/ipv6tests/Tests.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/net/ipv6tests/Tests.java Wed Jul 05 17:18:12 2017 +0200 @@ -248,7 +248,8 @@ } while (addrs.hasMoreElements()) { InetAddress addr = (InetAddress) addrs.nextElement(); - if (filter.isInstance (addr) && !addr.isLoopbackAddress()) { + if (filter.isInstance (addr) && !addr.isLoopbackAddress() + && !addr.isAnyLocalAddress()) { if (Arrays.equals (addr.getAddress(), fe80_loopback)) { continue; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/BufferPoolMXBean/Basic.java --- a/jdk/test/java/nio/BufferPoolMXBean/Basic.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/BufferPoolMXBean/Basic.java Wed Jul 05 17:18:12 2017 +0200 @@ -24,6 +24,7 @@ /* @test * @bug 6606598 * @summary Unit test for java.nio.BufferPoolMXBean + * @run main/othervm Basic */ import java.nio.ByteBuffer; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/MappedByteBuffer/Basic.java --- a/jdk/test/java/nio/MappedByteBuffer/Basic.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/MappedByteBuffer/Basic.java Wed Jul 05 17:18:12 2017 +0200 @@ -24,6 +24,7 @@ /* @test * @bug 4462336 * @summary Simple MappedByteBuffer tests + * @run main/othervm Basic */ import java.io.*; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/MappedByteBuffer/Force.java --- a/jdk/test/java/nio/MappedByteBuffer/Force.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/MappedByteBuffer/Force.java Wed Jul 05 17:18:12 2017 +0200 @@ -24,6 +24,7 @@ /* @test * @bug 4625907 * @summary Testing force() + * @run main/othervm Force */ import java.io.*; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/MappedByteBuffer/ZeroMap.java --- a/jdk/test/java/nio/MappedByteBuffer/ZeroMap.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/MappedByteBuffer/ZeroMap.java Wed Jul 05 17:18:12 2017 +0200 @@ -24,6 +24,7 @@ /* @test * @bug 4802340 * @summary Testing force(), load() isLoaded() of zero len MBB + * @run main/othervm ZeroMap */ import java.io.*; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java --- a/jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java Wed Jul 05 17:18:12 2017 +0200 @@ -29,6 +29,7 @@ import java.nio.ByteBuffer; import java.nio.channels.*; import java.net.*; +import java.util.*; import java.util.concurrent.*; import java.io.IOException; @@ -44,8 +45,12 @@ final AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open() .bind(new InetSocketAddress(0)); + final List accepted = new ArrayList(); listener.accept((Void)null, new CompletionHandler() { public void completed(AsynchronousSocketChannel ch, Void att) { + synchronized (accepted) { + accepted.add(ch); + } listener.accept((Void)null, this); } public void failed(Throwable exc, Void att) { @@ -58,6 +63,14 @@ test(sa, true, false); test(sa, false, true); test(sa, true, true); + + // clean-up + listener.close(); + synchronized (accepted) { + for (AsynchronousSocketChannel ch: accepted) { + ch.close(); + } + } } static void test(SocketAddress sa, diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java --- a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java Wed Jul 05 17:18:12 2017 +0200 @@ -32,6 +32,7 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; +import java.io.IOException; /** * Tests that the completion handler is invoked by a thread with @@ -81,14 +82,18 @@ listener.accept((Void)null, new CompletionHandler() { public void completed(final AsynchronousSocketChannel ch, Void att) { listener.accept((Void)null, this); - final ByteBuffer buf = ByteBuffer.allocate(100); - ch.read(buf, (Void)null, new CompletionHandler() { - public void completed(Integer bytesRead, Void att) { - buf.clear(); - ch.read(buf, (Void)null, this); + ch.read(buf, ch, new CompletionHandler() { + public void completed(Integer bytesRead, AsynchronousSocketChannel ch) { + if (bytesRead < 0) { + try { ch.close(); } catch (IOException ignore) { } + } else { + buf.clear(); + ch.read(buf, ch, this); + } } - public void failed(Throwable exc, Void att) { + public void failed(Throwable exc, AsynchronousSocketChannel ch) { + try { ch.close(); } catch (IOException ignore) { } } }); } @@ -100,7 +105,8 @@ // create 3-10 channels, each in its own group final int groupCount = 3 + rand.nextInt(8); - final AsynchronousSocketChannel[] channel = new AsynchronousSocketChannel[groupCount]; + AsynchronousChannelGroup[] groups = new AsynchronousChannelGroup[groupCount]; + final AsynchronousSocketChannel[] channels = new AsynchronousSocketChannel[groupCount]; for (int i=0; i() { + channels[0].write(getBuffer(), 0, new CompletionHandler() { public void completed(Integer bytesWritten, Integer groupId) { if (bytesWritten != 1) fail("Expected 1 byte to be written"); @@ -129,7 +136,7 @@ fail("Handler invoked by thread with the wrong identity"); if (writeCount.decrementAndGet() > 0) { int id = rand.nextInt(groupCount); - channel[id].write(getBuffer(), id, this); + channels[id].write(getBuffer(), id, this); } else { done.countDown(); } @@ -139,8 +146,16 @@ } }); - // wait until + // wait until done done.await(); + + // clean-up + for (AsynchronousSocketChannel ch: channels) + ch.close(); + for (AsynchronousChannelGroup group: groups) + group.shutdownNow(); + listener.close(); + if (failed.get()) throw new RuntimeException("Test failed - see log for details"); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java --- a/jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java Wed Jul 05 17:18:12 2017 +0200 @@ -371,17 +371,22 @@ static void doMulticastTests() throws Exception { final byte[] msg = "hello".getBytes(); + InetAddress lh = InetAddress.getLocalHost(); + NetworkInterface interf = NetworkInterface.getByInetAddress(lh); + if (interf.isLoopback() || !interf.supportsMulticast()) { + System.out.println("Multicasting not tested"); + return; + } + AsynchronousDatagramChannel ch = AsynchronousDatagramChannel .open(StandardProtocolFamily.INET, null) .setOption(StandardSocketOption.SO_REUSEADDR, true) .bind(new InetSocketAddress(0)); - InetAddress lh = InetAddress.getLocalHost(); int port = ((InetSocketAddress)(ch.getLocalAddress())).getPort(); // join group InetAddress group = InetAddress.getByName("225.4.5.6"); - NetworkInterface interf = NetworkInterface.getByInetAddress(lh); MembershipKey key = ch.join(group, interf); // check key diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java --- a/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java Wed Jul 05 17:18:12 2017 +0200 @@ -45,16 +45,18 @@ File blah = File.createTempFile("blah", null); blah.deleteOnExit(); - final AsynchronousFileChannel ch = AsynchronousFileChannel + AsynchronousFileChannel ch = AsynchronousFileChannel .open(blah.toPath(), READ, WRITE); + try { + // run tests + testUsingCompletionHandlers(ch); + testUsingWaitOnResult(ch); + testInterruptHandlerThread(ch); + } finally { + ch.close(); + } - // run tests - testUsingCompletionHandlers(ch); - testUsingWaitOnResult(ch); - testInterruptHandlerThread(ch); - - // close channel and invoke test that expects channel to be closed - ch.close(); + // run test that expects channel to be closed testClosedChannel(ch); // these tests open the file themselves @@ -63,6 +65,9 @@ testAsynchronousClose(blah.toPath()); testCancel(blah.toPath()); testTruncate(blah.toPath()); + + // eagerly clean-up + blah.delete(); } /* diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java --- a/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java Wed Jul 05 17:18:12 2017 +0200 @@ -53,13 +53,17 @@ LockSlaveMirror slave = startLockSlave(); try { - // create temporary file + // create temporary file File blah = File.createTempFile("blah", null); blah.deleteOnExit(); + // run tests testLockProtocol(blah, slave); testAsyncClose(blah, slave); + // eagerly clean-up + blah.delete(); + } finally { slave.shutdown(); } @@ -150,7 +154,12 @@ String sep = FileSystems.getDefault().getSeparator(); String command = System.getProperty("java.home") + - sep + "bin" + sep + "java Lock -lockslave " + port; + sep + "bin" + sep + "java"; + String testClasses = System.getProperty("test.classes"); + if (testClasses != null) + command += " -cp " + testClasses; + command += " Lock -lockslave " + port; + Process p = Runtime.getRuntime().exec(command); IOHandler.handle(p.getInputStream()); IOHandler.handle(p.getErrorStream()); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/AsynchronousFileChannel/LotsOfWrites.java --- a/jdk/test/java/nio/channels/AsynchronousFileChannel/LotsOfWrites.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/LotsOfWrites.java Wed Jul 05 17:18:12 2017 +0200 @@ -135,6 +135,7 @@ latch.await(); // verify content of each file + boolean failed = false; byte[] buf = new byte[8192]; for (int i=0; i 0) { for (int j=0; j 0) { out.println(); throw new RuntimeException("Some tests failed"); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/FileChannel/TryLock.java --- a/jdk/test/java/nio/channels/FileChannel/TryLock.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/FileChannel/TryLock.java Wed Jul 05 17:18:12 2017 +0200 @@ -56,7 +56,6 @@ public static void test1(boolean shared, boolean trylock) throws Exception { File testFile = File.createTempFile("test1", null); - testFile.deleteOnExit(); FileInputStream fis = new FileInputStream(testFile); FileChannel fc = fis.getChannel(); FileLock fl = null; @@ -73,12 +72,13 @@ } finally { if (fl != null) fl.release(); + fc.close(); + testFile.delete(); } } public static void test2(boolean shared, boolean trylock) throws Exception { File testFile = File.createTempFile("test2", null); - testFile.deleteOnExit(); FileOutputStream fis = new FileOutputStream(testFile); FileChannel fc = fis.getChannel(); FileLock fl = null; @@ -95,19 +95,25 @@ } finally { if (fl != null) fl.release(); + fc.close(); + testFile.delete(); } } public static void test3(boolean shared, boolean trylock) throws Exception { File testFile = File.createTempFile("test3", null); - testFile.deleteOnExit(); RandomAccessFile fis = new RandomAccessFile(testFile, "rw"); FileChannel fc = fis.getChannel(); - FileLock fl = null; - if (trylock) - fl = fc.tryLock(0, fc.size(), shared); - else - fl = fc.lock(0, fc.size(), shared); - fl.release(); + try { + FileLock fl = null; + if (trylock) + fl = fc.tryLock(0, fc.size(), shared); + else + fl = fc.lock(0, fc.size(), shared); + fl.release(); + } finally { + fc.close(); + testFile.delete(); + } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/FileChannel/Write.java --- a/jdk/test/java/nio/channels/FileChannel/Write.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/FileChannel/Write.java Wed Jul 05 17:18:12 2017 +0200 @@ -25,6 +25,7 @@ * @test * @bug 4475533 4698138 4638365 4796221 * @summary Test FileChannel write + * @run main/othervm Write */ import java.nio.channels.*; @@ -46,23 +47,25 @@ // Test to see that offset > length does not throw exception static void test1() throws Exception { - File testFile = File.createTempFile("test1", null); - testFile.deleteOnExit(); - ByteBuffer[] dsts = new ByteBuffer[4]; for (int i=0; i<4; i++) dsts[i] = ByteBuffer.allocateDirect(10); - FileOutputStream fos = new FileOutputStream(testFile); - FileChannel fc = fos.getChannel(); - fc.write(dsts, 2, 1); - fos.close(); + File testFile = File.createTempFile("test1", null); + try { + FileOutputStream fos = new FileOutputStream(testFile); + FileChannel fc = fos.getChannel(); + fc.write(dsts, 2, 1); + fos.close(); + } finally { + testFile.delete(); + } } // Test to see that the appropriate buffers are updated static void test2() throws Exception { File testFile = File.createTempFile("test2", null); - testFile.deleteOnExit(); + testFile.delete(); ByteBuffer[] srcs = new ByteBuffer[4]; for (int i=0; i<4; i++) srcs[i] = ByteBuffer.allocateDirect(10); @@ -74,25 +77,34 @@ FileOutputStream fos = new FileOutputStream(testFile); FileChannel fc = fos.getChannel(); - fc.write(srcs, 1, 2); - fos.close(); + try { + fc.write(srcs, 1, 2); + } finally { + fc.close(); + } FileInputStream fis = new FileInputStream(testFile); fc = fis.getChannel(); - ByteBuffer bb = ByteBuffer.allocateDirect(10); - fc.read(bb); - bb.flip(); - if (bb.get() != 2) - throw new RuntimeException("Write failure"); - if (bb.get() != 3) - throw new RuntimeException("Write failure"); try { - bb.get(); - throw new RuntimeException("Write failure"); - } catch (BufferUnderflowException bufe) { - // correct result + ByteBuffer bb = ByteBuffer.allocateDirect(10); + fc.read(bb); + bb.flip(); + if (bb.get() != 2) + throw new RuntimeException("Write failure"); + if (bb.get() != 3) + throw new RuntimeException("Write failure"); + try { + bb.get(); + throw new RuntimeException("Write failure"); + } catch (BufferUnderflowException bufe) { + // correct result + } + } finally { + fc.close(); } - fis.close(); + + // eagerly clean-up + testFile.delete(); } // Test write to a negative position (bug 4698138). diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Pipe/NonBlocking.java --- a/jdk/test/java/nio/channels/Pipe/NonBlocking.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Pipe/NonBlocking.java Wed Jul 05 17:18:12 2017 +0200 @@ -41,12 +41,17 @@ static void test1() throws Exception { Pipe p = Pipe.open(); - p.sink().configureBlocking(false); - if (p.sink().isBlocking()) - throw new Exception("Sink still blocking"); - p.source().configureBlocking(false); - if (p.source().isBlocking()) - throw new Exception("Source still blocking"); + try { + p.sink().configureBlocking(false); + if (p.sink().isBlocking()) + throw new Exception("Sink still blocking"); + p.source().configureBlocking(false); + if (p.source().isBlocking()) + throw new Exception("Source still blocking"); + } finally { + p.sink().close(); + p.source().close(); + } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Pipe/SelectPipe.java --- a/jdk/test/java/nio/channels/Pipe/SelectPipe.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Pipe/SelectPipe.java Wed Jul 05 17:18:12 2017 +0200 @@ -78,10 +78,12 @@ totalRead += bytesRead; } while(totalRead < 10); + sink.close(); + source.close(); + selector.close(); + for(int i=0; i<10; i++) if (outgoingdata.get(i) != incomingdata.get(i)) throw new Exception("Pipe failed"); - sink.close(); - source.close(); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SelectionKey/AtomicAttachTest.java --- a/jdk/test/java/nio/channels/SelectionKey/AtomicAttachTest.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SelectionKey/AtomicAttachTest.java Wed Jul 05 17:18:12 2017 +0200 @@ -58,6 +58,11 @@ }; t.join(); + + pipe.sink().close(); + pipe.source().close(); + selector.close(); + int count = errorCount.get(); if (count > 0) { throw new RuntimeException("Error count:" + count); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/BasicAccept.java --- a/jdk/test/java/nio/channels/Selector/BasicAccept.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/BasicAccept.java Wed Jul 05 17:18:12 2017 +0200 @@ -36,49 +36,60 @@ public class BasicAccept { - public static int TEST_PORT = 40170; - - static void server() throws Exception { + static void server(ServerSocketChannel ssc) throws Exception { Selector acceptSelector = Selector.open(); - ServerSocketChannel ssc = ServerSocketChannel.open(); - ssc.configureBlocking(false); - InetAddress lh = InetAddress.getLocalHost(); - InetSocketAddress isa - = new InetSocketAddress(lh, SelectorTest.TEST_PORT); - ssc.socket().bind(isa); - SelectionKey acceptKey - = ssc.register(acceptSelector, SelectionKey.OP_ACCEPT); - for (;;) { - if (acceptSelector.select() == 0) - continue; - Set readyKeys = acceptSelector.selectedKeys(); - Iterator i = readyKeys.iterator(); - while (i.hasNext()) { - SelectionKey sk = (SelectionKey)i.next(); - i.remove(); - ServerSocketChannel nextReady - = (ServerSocketChannel)sk.channel(); - SocketChannel sc = nextReady.accept(); - ByteBuffer bb = ByteBuffer.wrap(new byte[] { 42 }); - sc.write(bb); + try { + ssc.configureBlocking(false); + SelectionKey acceptKey + = ssc.register(acceptSelector, SelectionKey.OP_ACCEPT); + for (;;) { + int n = acceptSelector.select(); + if (Thread.interrupted()) + break; + if (n == 0) + continue; + Set readyKeys = acceptSelector.selectedKeys(); + Iterator i = readyKeys.iterator(); + while (i.hasNext()) { + SelectionKey sk = i.next(); + i.remove(); + ServerSocketChannel nextReady + = (ServerSocketChannel)sk.channel(); + SocketChannel sc = nextReady.accept(); + ByteBuffer bb = ByteBuffer.wrap(new byte[] { 42 }); + sc.write(bb); + sc.close(); + } + } + } finally { + acceptSelector.close(); + } + } + + private static class Server extends TestThread { + final ServerSocketChannel ssc; + Server() throws IOException { + super("Server", System.err); + this.ssc = ServerSocketChannel.open() + .bind(new InetSocketAddress(0)); + } + int port() { + return ssc.socket().getLocalPort(); + } + void go() throws Exception { + try { + server(ssc); + } finally { + ssc.close(); } } } - private static class Server extends TestThread { - Server() { - super("Server", System.err); - } - void go() throws Exception { - server(); - } - } - - static void client() throws Exception { + static void client(int port) throws Exception { // Get a connection from the server InetAddress lh = InetAddress.getLocalHost(); InetSocketAddress isa - = new InetSocketAddress(lh, SelectorTest.TEST_PORT); + = new InetSocketAddress(lh, port); int connectFailures = 0; boolean result = false; SocketChannel sc = SocketChannel.open(); @@ -122,17 +133,17 @@ if (bb.get(0) != 42) throw new RuntimeException("Read wrong byte from server"); System.err.println("Read from server"); + sc.close(); } public static void main(String[] args) throws Exception { - if (args.length == 0) { - Server server = new Server(); - server.start(); - client(); - } else if (args[0].equals("client")) { - client(); - } else if (args[0].equals("server")) { - server(); + Server server = new Server(); + server.start(); + try { + client(server.port()); + } finally { + server.interrupt(); + server.finish(2000); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/BasicConnect.java --- a/jdk/test/java/nio/channels/Selector/BasicConnect.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/BasicConnect.java Wed Jul 05 17:18:12 2017 +0200 @@ -83,10 +83,13 @@ ByteBuffer bb2 = ByteBuffer.allocateDirect(100); int n = sc.read(bb2); bb2.flip(); + + sc.close(); + connectSelector.close(); + if (!bb.equals(bb2)) throw new Exception("Echoed bytes incorrect: Sent " + bb + ", got " + bb2); - sc.close(); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/CheckLocking.java --- a/jdk/test/java/nio/channels/Selector/CheckLocking.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/CheckLocking.java Wed Jul 05 17:18:12 2017 +0200 @@ -61,5 +61,7 @@ doSelect(); sk.interestOps(SelectionKey.OP_READ); selector.wakeup(); + sc.close(); + selector.close(); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/CloseInvalidatesKeys.java --- a/jdk/test/java/nio/channels/Selector/CloseInvalidatesKeys.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/CloseInvalidatesKeys.java Wed Jul 05 17:18:12 2017 +0200 @@ -33,12 +33,16 @@ public static void main (String [] args) throws Exception { DatagramChannel ch = DatagramChannel.open(); - ch.configureBlocking(false); - Selector sel = Selector.open(); - SelectionKey key = ch.register(sel, SelectionKey.OP_WRITE); - sel.close(); - if (key.isValid()) - throw new Exception("Key valid after selector closed"); + try { + ch.configureBlocking(false); + Selector sel = Selector.open(); + SelectionKey key = ch.register(sel, SelectionKey.OP_WRITE); + sel.close(); + if (key.isValid()) + throw new Exception("Key valid after selector closed"); + } finally { + ch.close(); + } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/CloseWhenKeyIdle.java --- a/jdk/test/java/nio/channels/Selector/CloseWhenKeyIdle.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/CloseWhenKeyIdle.java Wed Jul 05 17:18:12 2017 +0200 @@ -111,10 +111,14 @@ // select should block int spinCount = 0; + boolean failed = false; for (;;) { int n = sel.select(); - if (n > 0) - throw new RuntimeException("channel should not be selected"); + if (n > 0) { + System.err.println("Channel should not be selected!!!"); + failed = true; + break; + } // wakeup if (wakeupDone) @@ -123,10 +127,19 @@ // wakeup for no reason - if it happens a few times then we have a // problem spinCount++; - if (spinCount >= 3) - throw new RuntimeException("Selector appears to be spinning"); + if (spinCount >= 3) { + System.err.println("Selector appears to be spinning"); + failed = true; + break; + } } + sc1.close(); + sel.close(); + + if (failed) + throw new RuntimeException("Test failed"); + System.out.println("PASS"); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/Connect.java --- a/jdk/test/java/nio/channels/Selector/Connect.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/Connect.java Wed Jul 05 17:18:12 2017 +0200 @@ -25,7 +25,6 @@ * @bug 4511624 * @summary Test Making lots of Selectors * @library .. - * @run main/timeout=240 Connect */ import java.io.*; @@ -38,7 +37,7 @@ public class Connect { static int success = 0; - static int LIMIT = 500; + static int LIMIT = 100; public static void main(String[] args) throws Exception { scaleTest(); @@ -51,29 +50,30 @@ for (int j=0; j 0) { - Set readyKeys = RSelector.selectedKeys(); - Iterator i = readyKeys.iterator(); + Set readyKeys = RSelector.selectedKeys(); + Iterator i = readyKeys.iterator(); while (i.hasNext()) { - SelectionKey sk = (SelectionKey)i.next(); + SelectionKey sk = i.next(); SocketChannel nextReady = (SocketChannel)sk.channel(); - result = nextReady.finishConnect(); + connected = nextReady.finishConnect(); } + readyKeys.clear(); } } RSelector.close(); } - read(sc); + readAndClose(sc); } } - static void read(SocketChannel sc) throws Exception { + static void readAndClose(SocketChannel sc) throws Exception { ByteBuffer bb = ByteBuffer.allocateDirect(100); int n = 0; while (n == 0) // Note this is not a rigorous check for done reading diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/ConnectWrite.java --- a/jdk/test/java/nio/channels/Selector/ConnectWrite.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/ConnectWrite.java Wed Jul 05 17:18:12 2017 +0200 @@ -45,8 +45,8 @@ Selector selector = SelectorProvider.provider().openSelector(); InetAddress myAddress=InetAddress.getByName(TestUtil.HOST); InetSocketAddress isa = new InetSocketAddress(myAddress, port); + SocketChannel sc = SocketChannel.open(); try { - SocketChannel sc = SocketChannel.open(); sc.configureBlocking(false); SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT); boolean result = sc.connect(isa); @@ -80,6 +80,7 @@ } } } finally { + sc.close(); selector.close(); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/HelperSlowToDie.java --- a/jdk/test/java/nio/channels/Selector/HelperSlowToDie.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/HelperSlowToDie.java Wed Jul 05 17:18:12 2017 +0200 @@ -33,9 +33,15 @@ public class HelperSlowToDie { private static final int CHANNELS_PER_THREAD = 1023; + private static final int TEST_ITERATIONS = 200; private static volatile boolean done; public static void main(String[] args) throws IOException { + if (!System.getProperty("os.name").startsWith("Windows")) { + System.out.println("Test skipped as it verifies a Windows specific bug"); + return; + } + Selector sel = Selector.open(); // register channels @@ -60,7 +66,7 @@ new Thread(busy).start(); // Loop changing the number of channels from 1023 to 1024 and back. - for (int i=0; i<1000; i++) { + for (int i=0; i 0) { - keysAdded = selector.select(1000); - if (keysAdded > 0) - throw new Exception("Same key reported added twice"); + try { + SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT); + int keysAdded = selector.select(); + if (keysAdded > 0) { + keysAdded = selector.select(1000); + if (keysAdded > 0) + throw new Exception("Same key reported added twice"); + } + } finally { + selector.close(); + sc.close(); } - sc.close(); } public static void main(String[] args) throws Exception { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/LotsOfChannels.java --- a/jdk/test/java/nio/channels/Selector/LotsOfChannels.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/LotsOfChannels.java Wed Jul 05 17:18:12 2017 +0200 @@ -35,19 +35,11 @@ public class LotsOfChannels { - private final static int PIPES_COUNT = 1900; + private final static int PIPES_COUNT = 256; private final static int BUF_SIZE = 8192; private final static int LOOPS = 10; public static void main(String[] argv) throws Exception { - - - String os = System.getProperty("os.name"); - if (!(os.equals("Windows NT") - || os.equals("Windows 2000") - || os.equals("Windows XP"))) - return; - Pipe[] pipes = new Pipe[PIPES_COUNT]; Pipe pipe = Pipe.open(); Pipe.SinkChannel sink = pipe.sink(); @@ -72,6 +64,13 @@ sel.selectedKeys().clear(); source.read(ByteBuffer.allocate(BUF_SIZE)); } + + for (int i = 0; i < PIPES_COUNT; i++ ) { + pipes[i].sink().close(); + pipes[i].source().close(); + } + pipe.sink().close(); + pipe.source().close(); sel.close(); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/OutOfBand.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/Selector/OutOfBand.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 6213702 + * @summary OOB data causes a SocketChannel, with OOBINLINE disabled, to be + * selected + */ + +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.io.IOException; + +public class OutOfBand { + + public static void main(String[] args) throws Exception { + ServerSocketChannel ssc = null; + SocketChannel sc = null; + Selector sel = null; + Socket s = null; + + try { + // establish loopback connection. + ssc = ServerSocketChannel.open().bind(new InetSocketAddress(0)); + s = new Socket(InetAddress.getLocalHost(), + ssc.socket().getLocalPort()); + sc = ssc.accept(); + + sel = Selector.open(); + sc.configureBlocking(false); + sc.register(sel, SelectionKey.OP_READ); + + // OOB data should be disabled by default + if (sc.socket().getOOBInline()) + throw new RuntimeException("SO_OOBINLINE enabled"); + test(s, false, 0, 0, sel); + test(s, false, 512, 0, sel); + test(s, false, 0, 512, sel); + test(s, false, 512, 512, sel); + + // enable SO_OOBINLINE + sc.socket().setOOBInline(true); + + // OOB data should be received + test(s, true, 0, 0, sel); + test(s, true, 512, 0, sel); + test(s, true, 0, 512, sel); + test(s, true, 512, 512, sel); + + } finally { + if (sel != null) sel.close(); + if (sc != null) sc.close(); + if (ssc != null) ssc.close(); + if (s != null) sc.close(); + } + } + + static void test(Socket s, boolean urgentExpected, + int bytesBefore, int bytesAfter, + Selector sel) + throws IOException + { + // send data + int bytesExpected = 0; + if (bytesBefore > 0) { + s.getOutputStream().write(new byte[bytesBefore]); + bytesExpected += bytesBefore; + } + s.sendUrgentData(0xff); + if (urgentExpected) + bytesExpected++; + if (bytesAfter > 0) { + s.getOutputStream().write(new byte[bytesAfter]); + bytesExpected += bytesAfter; + } + + // receive data, checking for spurious wakeups and reads + int spuriousWakeups = 0; + int spuriousReads = 0; + int bytesRead = 0; + ByteBuffer bb = ByteBuffer.allocate(100); + for (;;) { + int n = sel.select(2000); + if (n == 0) { + if (bytesRead == bytesExpected) { + System.out.format("Selector wakeups %d\tSpurious reads %d%n", + spuriousWakeups, spuriousReads); + return; + } + if (++spuriousWakeups >= 3) + throw new RuntimeException("Selector appears to be spinning" + + " or data not received"); + continue; + } + if (n > 1) + throw new RuntimeException("More than one key selected????"); + SelectionKey key = sel.selectedKeys().iterator().next(); + bb.clear(); + n = ((SocketChannel)key.channel()).read(bb); + if (n == 0) { + if (++spuriousReads >=3) + throw new RuntimeException("Too many spurious reads"); + } else { + bytesRead += n; + if (bytesRead > bytesExpected) + throw new RuntimeException("Received more than expected"); + } + sel.selectedKeys().clear(); + } + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/RegAfterPreClose.java --- a/jdk/test/java/nio/channels/Selector/RegAfterPreClose.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/RegAfterPreClose.java Wed Jul 05 17:18:12 2017 +0200 @@ -35,6 +35,7 @@ public class RegAfterPreClose { + static final int TEST_ITERATIONS = 300; static volatile boolean done; /** @@ -96,26 +97,21 @@ } }; - // schedule test to run for 1 minute - Executors.newScheduledThreadPool(1, factory).schedule(new Runnable() { - public void run() { - done = true; - sel.wakeup(); - }}, 1, TimeUnit.MINUTES); - // create Executor that handles tasks that closes channels // "asynchronously" - this creates the conditions to provoke the bug. - Executor executor = Executors.newFixedThreadPool(2, factory); + ExecutorService executor = Executors.newFixedThreadPool(2, factory); // submit task that connects to listener executor.execute(new Connector(ssc.socket().getLocalPort())); // loop accepting connections until done (or an IOException is thrown) - while (!done) { + int remaining = TEST_ITERATIONS; + while (remaining > 0) { sel.select(); if (key.isAcceptable()) { SocketChannel sc = ssc.accept(); if (sc != null) { + remaining--; sc.configureBlocking(false); sc.register(sel, SelectionKey.OP_READ); executor.execute(new Closer(sc)); @@ -123,5 +119,8 @@ } sel.selectedKeys().clear(); } + done = true; + sel.close(); + executor.shutdown(); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/SelectAndCancel.java --- a/jdk/test/java/nio/channels/Selector/SelectAndCancel.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/SelectAndCancel.java Wed Jul 05 17:18:12 2017 +0200 @@ -31,11 +31,7 @@ import java.net.*; public class SelectAndCancel { - static ServerSocketChannel ssc; - static Selector selector; static SelectionKey sk; - static InetSocketAddress isa; - public static int TEST_PORT = 40170; /* * CancelledKeyException is the failure symptom of 4729342 @@ -43,17 +39,17 @@ * seen immediately when the bug is present. */ public static void main(String[] args) throws Exception { - InetAddress lh = InetAddress.getLocalHost(); - isa = new InetSocketAddress(lh, TEST_PORT); - selector = Selector.open(); - ssc = ServerSocketChannel.open(); + final Selector selector = Selector.open(); + final ServerSocketChannel ssc = + ServerSocketChannel.open().bind(new InetSocketAddress(0)); + final InetSocketAddress isa = + new InetSocketAddress(InetAddress.getLocalHost(), ssc.socket().getLocalPort()); // Create and start a selector in a separate thread. new Thread(new Runnable() { public void run() { try { ssc.configureBlocking(false); - ssc.socket().bind(isa); sk = ssc.register(selector, SelectionKey.OP_ACCEPT); selector.select(); } catch (IOException e) { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/SelectorLimit.java --- a/jdk/test/java/nio/channels/Selector/SelectorLimit.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/SelectorLimit.java Wed Jul 05 17:18:12 2017 +0200 @@ -26,6 +26,8 @@ * @summary Ensure that a Selector can return at least 100 selected keys * @author Mark Reinhold * @library .. + * @build SelectorLimit + * @run main/othervm SelectorLimit */ import java.io.*; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/SelectorTest.java --- a/jdk/test/java/nio/channels/Selector/SelectorTest.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/SelectorTest.java Wed Jul 05 17:18:12 2017 +0200 @@ -57,13 +57,13 @@ */ public static void main(String[] args) throws Exception { if (args.length == 0) { - InetSocketAddress isa - = new InetSocketAddress(InetAddress.getLocalHost(), TEST_PORT); - Server server = new Server(isa); + Server server = new Server(0); server.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { } + InetSocketAddress isa + = new InetSocketAddress(InetAddress.getLocalHost(), server.port()); Client client = new Client(isa); client.start(); if ((server.finish(FINISH_TIME) & client.finish(FINISH_TIME)) == 0) @@ -74,9 +74,7 @@ if (args.length > 1) TEST_PORT = Integer.parseInt(args[1]); - InetSocketAddress isa - = new InetSocketAddress(InetAddress.getLocalHost(), TEST_PORT); - Server server = new Server(isa); + Server server = new Server(TEST_PORT); server.start(); if (server.finish(FINISH_TIME) == 0) throw new Exception("Failure"); @@ -136,18 +134,22 @@ } static class Server extends TestThread { + private final ServerSocketChannel ssc; private List socketList = new ArrayList(); private ServerSocket ss; private int connectionsAccepted = 0; private Selector pollSelector; private Selector acceptSelector; - private InetSocketAddress isa; private Set pkeys; private Set pskeys; - Server(InetSocketAddress isa) { + Server(int port) throws IOException { super("Server", SelectorTest.log); - this.isa = isa; + this.ssc = ServerSocketChannel.open().bind(new InetSocketAddress(port)); + } + + int port() { + return ssc.socket().getLocalPort(); } public void go() throws Exception { @@ -162,11 +164,7 @@ requestThread.start(); - ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking(false); - ssc.socket().setReuseAddress(true); - ssc.socket().bind(isa); - SelectionKey acceptKey = ssc.register(acceptSelector, SelectionKey.OP_ACCEPT); while(connectionsAccepted < SelectorTest.NUM_CLIENTS) { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/WakeupNow.java --- a/jdk/test/java/nio/channels/Selector/WakeupNow.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/WakeupNow.java Wed Jul 05 17:18:12 2017 +0200 @@ -44,10 +44,15 @@ p.source().configureBlocking(false); p.source().register(sel, SelectionKey.OP_READ); sel.wakeup(); + // ensure wakeup is consumed by selectNow + Thread.sleep(2000); sel.selectNow(); long startTime = System.currentTimeMillis(); int n = sel.select(2000); long endTime = System.currentTimeMillis(); + p.source().close(); + p.sink().close(); + sel.close(); if (endTime - startTime < 1000) throw new RuntimeException("test failed"); } @@ -60,10 +65,13 @@ Pipe p = Pipe.open(); p.source().configureBlocking(false); sel.wakeup(); + // ensure wakeup is consumed by selectNow + Thread.sleep(2000); sel.selectNow(); long startTime = System.currentTimeMillis(); int n = sel.select(2000); long endTime = System.currentTimeMillis(); + sel.close(); if (endTime - startTime < 1000) throw new RuntimeException("test failed"); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/WakeupOverflow.java --- a/jdk/test/java/nio/channels/Selector/WakeupOverflow.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/WakeupOverflow.java Wed Jul 05 17:18:12 2017 +0200 @@ -31,8 +31,12 @@ public class WakeupOverflow { public static void main( String[] args ) throws Exception { Selector selector = Selector.open(); - for(int i=0; i<10000; i++) { - selector.wakeup(); + try { + for(int i=0; i<10000; i++) { + selector.wakeup(); + } + } finally { + selector.close(); } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/Selector/WakeupSpeed.java --- a/jdk/test/java/nio/channels/Selector/WakeupSpeed.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/Selector/WakeupSpeed.java Wed Jul 05 17:18:12 2017 +0200 @@ -35,16 +35,19 @@ public static void main(String argv[]) throws Exception { int waitTime = 4000; Selector selector = Selector.open(); - - selector.wakeup(); + try { + selector.wakeup(); - long t1 = System.currentTimeMillis(); - selector.select(waitTime); - long t2 = System.currentTimeMillis(); - long totalTime = t2 - t1; + long t1 = System.currentTimeMillis(); + selector.select(waitTime); + long t2 = System.currentTimeMillis(); + long totalTime = t2 - t1; - if (totalTime > waitTime) - throw new RuntimeException("Test failed"); + if (totalTime > waitTime) + throw new RuntimeException("Test failed"); + } finally { + selector.close(); + } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/ServerSocketChannel/AcceptAddress.java --- a/jdk/test/java/nio/channels/ServerSocketChannel/AcceptAddress.java Wed Jul 05 17:17:22 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - * @summary test the address returned in socket from accept - */ - -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; - - -public class AcceptAddress { - - public static void main(String[] args) throws Exception { - InetAddress local = InetAddress.getLocalHost(); - InetSocketAddress isa = new InetSocketAddress(local, 5555); - - ServerSocketChannel ssc; - ssc = ServerSocketChannel.open(); - ssc.socket().bind(isa); - - SocketChannel sc; - sc = SocketChannel.open(); - sc.connect(isa); - - SocketChannel sc2 = ssc.accept(); - System.err.println("Socket connected to " + sc2); - } -} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/AdaptSocket.java --- a/jdk/test/java/nio/channels/SocketChannel/AdaptSocket.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/AdaptSocket.java Wed Jul 05 17:18:12 2017 +0200 @@ -78,8 +78,6 @@ throw x; } } - if (shouldTimeout) - throw new Exception("Connection did not time out"); } out.println("connected: " + so); out.println(" " + sc); @@ -118,8 +116,6 @@ } throw x; } - if (shouldTimeout) - throw new Exception("Read did not time out"); } static void testRead(String hn, int timeout, boolean shouldTimeout) diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/Bind.java --- a/jdk/test/java/nio/channels/SocketChannel/Bind.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/Bind.java Wed Jul 05 17:18:12 2017 +0200 @@ -31,13 +31,20 @@ public class Bind { public static void main(String[] args) throws Exception { + SocketChannel sc1 = SocketChannel.open(); try { - SocketChannel channel1 = SocketChannel.open(); - channel1.socket().bind(new InetSocketAddress(5555)); - SocketChannel channel2 = SocketChannel.open(); - channel2.socket().bind(new InetSocketAddress(5555)); + sc1.bind(new InetSocketAddress(0)); + int port = sc1.socket().getLocalPort(); + SocketChannel sc2 = SocketChannel.open(); + try { + sc2.bind(new InetSocketAddress(port)); + } finally { + sc2.close(); + } } catch (BindException be) { // Correct result + } finally { + sc1.close(); } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/Close.java --- a/jdk/test/java/nio/channels/SocketChannel/Close.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/Close.java Wed Jul 05 17:18:12 2017 +0200 @@ -56,8 +56,12 @@ static void testChannelClose() throws IOException { SelectionKey sk = open(); - sk.channel().close(); - check(sk); + try { + sk.channel().close(); + check(sk); + } finally { + sk.selector().close(); + } } public static void main(String[] args) throws Exception { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/CloseRegisteredChannel.java --- a/jdk/test/java/nio/channels/SocketChannel/CloseRegisteredChannel.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/CloseRegisteredChannel.java Wed Jul 05 17:18:12 2017 +0200 @@ -55,5 +55,8 @@ System.out.println ("Will hang here..."); int nb = slave.read (ByteBuffer.allocate (1024)); //System.out.println("read nb=" + nb); + + selector.close(); + server.close(); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/CloseTimeoutChannel.java --- a/jdk/test/java/nio/channels/SocketChannel/CloseTimeoutChannel.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/CloseTimeoutChannel.java Wed Jul 05 17:18:12 2017 +0200 @@ -33,11 +33,12 @@ import java.net.*; public class CloseTimeoutChannel { - final static int PORT=6347; public static void main(String args[]) throws Exception { + int port = -1; try { ServerSocketChannel listener=ServerSocketChannel.open(); - listener.socket().bind(new InetSocketAddress(PORT)); + listener.socket().bind(new InetSocketAddress(0)); + port = listener.socket().getLocalPort(); AcceptorThread thread=new AcceptorThread(listener); thread.start(); } catch (IOException e) { @@ -50,7 +51,7 @@ try { System.out.println("Establishing connection"); Socket socket=SocketChannel.open( - new InetSocketAddress("127.0.0.1", PORT)).socket(); + new InetSocketAddress("127.0.0.1", port)).socket(); OutputStream out=socket.getOutputStream(); InputStream in=socket.getInputStream(); @@ -98,7 +99,8 @@ Thread.sleep(100); } catch (InterruptedException e) { } - System.out.println(INDENT+"Listening on port "+ PORT); + System.out.println(INDENT+"Listening on port "+ + _listener.socket().getLocalPort()); ByteBuffer buf=ByteBuffer.allocate(5); Socket client=_listener.accept().socket();; System.out.println(INDENT+"Accepted client"); @@ -123,6 +125,8 @@ client.close(); } catch (IOException e) { System.out.println(INDENT+"Error accepting!"); + } finally { + try { _listener.close(); } catch (IOException ignore) { } } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/IsConnectable.java --- a/jdk/test/java/nio/channels/SocketChannel/IsConnectable.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/IsConnectable.java Wed Jul 05 17:18:12 2017 +0200 @@ -48,27 +48,31 @@ sc.connect(isa); Selector selector = SelectorProvider.provider().openSelector(); - SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT); - int keysAdded = selector.select(); - if (keysAdded > 0) { - boolean result = sc.finishConnect(); - if (result) { - keysAdded = selector.select(5000); - // 4750573: keysAdded should not be incremented when op is dropped - // from a key already in the selected key set - if (keysAdded > 0) - throw new Exception("Test failed: 4750573 detected"); - Set sel = selector.selectedKeys(); - Iterator i = sel.iterator(); - SelectionKey sk = (SelectionKey)i.next(); - // 4737146: isConnectable should be false while connected - if (sk.isConnectable()) - throw new Exception("Test failed: 4737146 detected"); + try { + SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT); + int keysAdded = selector.select(); + if (keysAdded > 0) { + boolean result = sc.finishConnect(); + if (result) { + keysAdded = selector.select(5000); + // 4750573: keysAdded should not be incremented when op is dropped + // from a key already in the selected key set + if (keysAdded > 0) + throw new Exception("Test failed: 4750573 detected"); + Set sel = selector.selectedKeys(); + Iterator i = sel.iterator(); + SelectionKey sk = i.next(); + // 4737146: isConnectable should be false while connected + if (sk.isConnectable()) + throw new Exception("Test failed: 4737146 detected"); + } + } else { + throw new Exception("Select failed"); } - } else { - throw new Exception("Select failed"); + } finally { + sc.close(); + selector.close(); } - sc.close(); } public static void main(String[] args) throws Exception { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/LocalAddress.java --- a/jdk/test/java/nio/channels/SocketChannel/LocalAddress.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/LocalAddress.java Wed Jul 05 17:18:12 2017 +0200 @@ -38,25 +38,33 @@ static void test1() throws Exception { InetAddress bogus = InetAddress.getByName("0.0.0.0"); - SocketChannel sc = SocketChannel.open(); InetSocketAddress saddr = new InetSocketAddress( InetAddress.getByName(TestUtil.HOST), 23); //Test1: connect only - sc.connect(saddr); - InetAddress isa = sc.socket().getLocalAddress(); - if (isa == null || isa.equals(bogus)) - throw new RuntimeException("test failed"); + SocketChannel sc = SocketChannel.open(); + try { + sc.connect(saddr); + InetAddress ia = sc.socket().getLocalAddress(); + if (ia == null || ia.equals(bogus)) + throw new RuntimeException("test failed"); + } finally { + sc.close(); + } //Test2: bind and connect sc = SocketChannel.open(); - sc.socket().bind(new InetSocketAddress(0)); - if (sc.socket().getLocalPort() == 0) - throw new RuntimeException("test failed"); - sc.socket().connect(saddr); - isa = sc.socket().getLocalAddress(); - if (isa == null || isa.isAnyLocalAddress()) - throw new RuntimeException("test failed"); + try { + sc.socket().bind(new InetSocketAddress(0)); + if (sc.socket().getLocalPort() == 0) + throw new RuntimeException("test failed"); + sc.socket().connect(saddr); + InetAddress ia = sc.socket().getLocalAddress(); + if (ia == null || ia.isAnyLocalAddress()) + throw new RuntimeException("test failed"); + } finally { + sc.close(); + } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/SocketInheritance.java --- a/jdk/test/java/nio/channels/SocketChannel/SocketInheritance.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/SocketInheritance.java Wed Jul 05 17:18:12 2017 +0200 @@ -105,7 +105,11 @@ // launch the child String cmd = System.getProperty("java.home") + File.separator + "bin" + - File.separator + "java SocketInheritance -child " + port; + File.separator + "java"; + String testClasses = System.getProperty("test.classes"); + if (testClasses != null) + cmd += " -cp " + testClasses; + cmd += " SocketInheritance -child " + port; Process p = Runtime.getRuntime().exec(cmd); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/Trivial.java --- a/jdk/test/java/nio/channels/SocketChannel/Trivial.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/Trivial.java Wed Jul 05 17:18:12 2017 +0200 @@ -33,22 +33,27 @@ public static void main(String[] args) throws Exception { SocketChannel sc = SocketChannel.open(); Selector sel = Selector.open(); - if (sc.keyFor(sel) != null) - throw new Exception("keyFor != null"); - sc.configureBlocking(false); - SelectionKey sk = sc.register(sel, SelectionKey.OP_READ, args); - if (sc.keyFor(sel) != sk) - throw new Exception("keyFor returned " + sc.keyFor(sel)); - if (sk.attachment() != args) - throw new Exception("attachment() returned " + sk.attachment()); - Trivial t = new Trivial(); - sk.attach(t); - if (sk.attachment() != t) - throw new Exception("Wrong attachment"); - sk.isReadable(); - sk.isWritable(); - sk.isConnectable(); - sk.isAcceptable(); + try { + if (sc.keyFor(sel) != null) + throw new Exception("keyFor != null"); + sc.configureBlocking(false); + SelectionKey sk = sc.register(sel, SelectionKey.OP_READ, args); + if (sc.keyFor(sel) != sk) + throw new Exception("keyFor returned " + sc.keyFor(sel)); + if (sk.attachment() != args) + throw new Exception("attachment() returned " + sk.attachment()); + Trivial t = new Trivial(); + sk.attach(t); + if (sk.attachment() != t) + throw new Exception("Wrong attachment"); + sk.isReadable(); + sk.isWritable(); + sk.isConnectable(); + sk.isAcceptable(); + } finally { + sel.close(); + sc.close(); + } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/SocketChannel/UnboundSocketTests.java --- a/jdk/test/java/nio/channels/SocketChannel/UnboundSocketTests.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/UnboundSocketTests.java Wed Jul 05 17:18:12 2017 +0200 @@ -57,39 +57,47 @@ System.out.println("\n-- SocketChannel --"); SocketChannel sc = SocketChannel.open(); + try { + check("getLocalPort()", sc.socket().getLocalPort(), -1); + checkIsAnyLocalAddress("getLocalAddress()", + sc.socket().getLocalAddress()); + check("getLocalSocketAddress()", sc.socket().getLocalSocketAddress(), null); - check("getLocalPort()", sc.socket().getLocalPort(), -1); - checkIsAnyLocalAddress("getLocalAddress()", - sc.socket().getLocalAddress()); - check("getLocalSocketAddress()", sc.socket().getLocalSocketAddress(), null); - - check("getPort()", sc.socket().getPort(), 0); - check("getInetAddress()", sc.socket().getInetAddress(), null); - check("getRemoteSocketAddress()", sc.socket().getRemoteSocketAddress(), null); - + check("getPort()", sc.socket().getPort(), 0); + check("getInetAddress()", sc.socket().getInetAddress(), null); + check("getRemoteSocketAddress()", sc.socket().getRemoteSocketAddress(), null); + } finally { + sc.close(); + } System.out.println("\n-- ServerSocketChannel --"); ServerSocketChannel ssc = ServerSocketChannel.open(); - - check("getLocalPort()", ssc.socket().getLocalPort(), -1); - check("getInetAddress()", ssc.socket().getInetAddress(), null); - check("getLocalSocketAddress()", ssc.socket().getLocalSocketAddress(), null); + try { + check("getLocalPort()", ssc.socket().getLocalPort(), -1); + check("getInetAddress()", ssc.socket().getInetAddress(), null); + check("getLocalSocketAddress()", ssc.socket().getLocalSocketAddress(), null); + } finally { + ssc.close(); + } System.out.println("\n-- DatagramChannel --"); DatagramChannel dc = DatagramChannel.open(); - - // not specified - check("getLocalPort()", dc.socket().getLocalPort(), 0); + try { + // not specified + check("getLocalPort()", dc.socket().getLocalPort(), 0); - checkIsAnyLocalAddress("getLocalAddress()", - dc.socket().getLocalAddress()); - check("getLocalSocketAddress()", dc.socket().getLocalSocketAddress(), null); + checkIsAnyLocalAddress("getLocalAddress()", + dc.socket().getLocalAddress()); + check("getLocalSocketAddress()", dc.socket().getLocalSocketAddress(), null); - check("getPort()", dc.socket().getPort(), -1); - check("getInetAddress()", dc.socket().getInetAddress(), null); - check("getRemoteSocketAddress()", dc.socket().getRemoteSocketAddress(), null); + check("getPort()", dc.socket().getPort(), -1); + check("getInetAddress()", dc.socket().getInetAddress(), null); + check("getRemoteSocketAddress()", dc.socket().getRemoteSocketAddress(), null); + } finally { + dc.close(); + } if (failures > 0) { throw new RuntimeException(failures + " sub-tests(s) failed."); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/etc/Shadow.java --- a/jdk/test/java/nio/channels/etc/Shadow.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/etc/Shadow.java Wed Jul 05 17:18:12 2017 +0200 @@ -35,7 +35,6 @@ public class Shadow { - private static final int PORT = 2019; static PrintStream log = System.err; private static void dump(ServerSocket s) { @@ -69,7 +68,7 @@ public static void main(String[] args) throws Exception { boolean useChannels = ((args.length == 0) || Boolean.valueOf(args[0]).booleanValue()); - int port = (args.length > 1 ? Integer.parseInt(args[1]) : PORT); + int port = (args.length > 1 ? Integer.parseInt(args[1]) : -1); // open server socket ServerSocket serverSocket; @@ -86,7 +85,8 @@ } // bind server socket to port - SocketAddress bindAddr = new InetSocketAddress(port); + SocketAddress bindAddr = + new InetSocketAddress((port == -1) ? 0 : port); serverSocket.bind(bindAddr); log.println("bound ServerSocket: " + serverSocket); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/ClosedStreams.java --- a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/ClosedStreams.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/ClosedStreams.java Wed Jul 05 17:18:12 2017 +0200 @@ -26,6 +26,8 @@ * @bug 4997227 * @summary Calling inheritedChannel() after FileDescriptor.in was closed * caused an InternalError to be thrown. + * @build ClosedStreams + * @run main/othervm ClosedStreams */ import java.io.FileDescriptor; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/charset/coders/BashStreams.java --- a/jdk/test/java/nio/charset/coders/BashStreams.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/charset/coders/BashStreams.java Wed Jul 05 17:18:12 2017 +0200 @@ -46,7 +46,7 @@ CharacterGenerator(long seed, String csn, int limit) { rand = new Random(seed); - this.max = Surrogate.UCS4_MAX + 1; + this.max = Character.MAX_CODE_POINT + 1; this.limit = limit; } @@ -77,17 +77,20 @@ int c; for (;;) { c = rand.nextInt(max); - if (Surrogate.is(c) || (c == 0xfffe) || (c == 0xffff)) + if ((Character.isBmpCodePoint(c) + && (Character.isSurrogate((char) c) + || (c == 0xfffe) || (c == 0xffff)))) continue; - if (Surrogate.neededFor(c) && (count == limit - 1)) + if (Character.isSupplementaryCodePoint(c) + && (count == limit - 1)) continue; break; } count++; - if (Surrogate.neededFor(c)) { + if (Character.isSupplementaryCodePoint(c)) { count++; - push(Surrogate.low(c)); - return Surrogate.high(c); + push(Character.lowSurrogate(c)); + return Character.highSurrogate(c); } return (char)c; } @@ -137,7 +140,7 @@ char d = cg.next(); if (c != d) { if (c == '?') { - if (Surrogate.isHigh(d)) + if (Character.isHighSurrogate(d)) cg.next(); continue; } @@ -187,7 +190,7 @@ w.write(ca, 0, n); count += n; } - if (Surrogate.isHigh(ca[n - 1])) + if (Character.isHighSurrogate(ca[n - 1])) w.write(cg.next()); w.close(); } @@ -253,7 +256,8 @@ if (!cg.hasNext()) break; char c = cg.next(); - if (Surrogate.isHigh(c) && (cb.remaining() == 1)) { + if (Character.isHighSurrogate(c) + && cb.remaining() == 1) { cg.push(c); break; } @@ -311,7 +315,7 @@ mismatchedEOF(csn, count + i, cg.count()); char d = cg.next(); if (c == '?') { - if (Surrogate.isHigh(d)) { + if (Character.isHighSurrogate(d)) { cg.next(); continue; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/charset/coders/Surrogate.java --- a/jdk/test/java/nio/charset/coders/Surrogate.java Wed Jul 05 17:17:22 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -public class Surrogate { - - public static final int UCS4_SURROGATE_MIN = 0x10000; - public static final int UCS4_MAX = (1 << 20) + UCS4_SURROGATE_MIN - 1; - - // UTF-16 surrogate-character ranges - // - public static final char MIN_HIGH = '\uD800'; - public static final char MAX_HIGH = '\uDBFF'; - public static final char MIN_LOW = '\uDC00'; - public static final char MAX_LOW = '\uDFFF'; - public static final char MIN = MIN_HIGH; - public static final char MAX = MAX_LOW; - - public static boolean neededFor(int uc) { - return (uc >= UCS4_SURROGATE_MIN) && (uc <= UCS4_MAX); - } - - public static boolean isHigh(int c) { - return (MIN_HIGH <= c) && (c <= MAX_HIGH); - } - - static char high(int uc) { - return (char)(0xd800 | (((uc - UCS4_SURROGATE_MIN) >> 10) & 0x3ff)); - } - - public static boolean isLow(int c) { - return (MIN_LOW <= c) && (c <= MAX_LOW); - } - - static char low(int uc) { - return (char)(0xdc00 | ((uc - UCS4_SURROGATE_MIN) & 0x3ff)); - } - - public static boolean is(int c) { - return (MIN <= c) && (c <= MAX); - } - - static int toUCS4(char c, char d) { - return (((c & 0x3ff) << 10) | (d & 0x3ff)) + 0x10000; - } - -} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/nio/charset/coders/Surrogates.java --- a/jdk/test/java/nio/charset/coders/Surrogates.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/nio/charset/coders/Surrogates.java Wed Jul 05 17:18:12 2017 +0200 @@ -42,9 +42,8 @@ static void initData() throws IOException { StringBuffer sb = new StringBuffer(); for (int i = 0; i < LEN; i++) { - int c = Surrogate.UCS4_SURROGATE_MIN + 1; - sb.append(Surrogate.high(c)); - sb.append(Surrogate.low(c)); + int c = Character.MIN_SUPPLEMENTARY_CODE_POINT + 1; + sb.append(Character.toChars(c)); } input = sb.toString().toCharArray(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/util/Arrays/Sorting.java --- a/jdk/test/java/util/Arrays/Sorting.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/java/util/Arrays/Sorting.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,10 +43,11 @@ // Array lengths used in a long run (default) private static final int[] LONG_RUN_LENGTHS = { - 1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000}; + 1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000 }; // Array lengths used in a short run - private static final int[] SHORT_RUN_LENGTHS = { 1, 2, 3, 21, 55, 1000, 10000 }; + private static final int[] SHORT_RUN_LENGTHS = { + 1, 2, 3, 21, 55, 1000, 10000 }; // Random initial values used in a long run (default) private static final long[] LONG_RUN_RANDOMS = {666, 0xC0FFEE, 999}; @@ -65,99 +66,338 @@ } long end = System.currentTimeMillis(); - out.format("PASS in %d sec.\n", Math.round((end - start) / 1E3)); + out.format("\nPASSED in %d sec.\n", Math.round((end - start) / 1E3)); } private static void testAndCheck(int[] lengths, long[] randoms) { + testEmptyAndNullIntArray(); + testEmptyAndNullLongArray(); + testEmptyAndNullShortArray(); + testEmptyAndNullCharArray(); + testEmptyAndNullByteArray(); + testEmptyAndNullFloatArray(); + testEmptyAndNullDoubleArray(); + for (long random : randoms) { reset(random); - for (int len : lengths) { - testAndCheckWithCheckSum(len, random); - } - reset(random); - - for (int len : lengths) { - testAndCheckWithScrambling(len, random); + for (int length : lengths) { + testAndCheckWithCheckSum(length, random); } reset(random); - for (int len : lengths) { - testAndCheckFloat(len, random); + for (int length : lengths) { + testAndCheckWithScrambling(length, random); + } + reset(random); + + for (int length : lengths) { + testAndCheckFloat(length, random); } reset(random); - for (int len : lengths) { - testAndCheckDouble(len, random); + for (int length : lengths) { + testAndCheckDouble(length, random); } reset(random); - for (int len : lengths) { - testAndCheckRange(len, random); + for (int length : lengths) { + testAndCheckRange(length, random); } reset(random); - for (int len : lengths) { - testAndCheckSubArray(len, random); + for (int length : lengths) { + testAndCheckSubArray(length, random); + } + reset(random); + + for (int length : lengths) { + testStable(length, random); } } } - private static void testAndCheckSubArray(int len, long random) { - int[] golden = new int[len]; + private static void testEmptyAndNullIntArray() { + ourDescription = "Check empty and null array"; + Arrays.sort(new int[] {}); + Arrays.sort(new int[] {}, 0, 0); + + try { + Arrays.sort((int[]) null); + } catch (NullPointerException expected) { + try { + Arrays.sort((int[]) null, 0, 0); + } catch (NullPointerException expected2) { + return; + } + failed("Arrays.sort(int[],fromIndex,toIndex) shouldn't " + + "catch null array"); + } + failed("Arrays.sort(int[]) shouldn't catch null array"); + } + + private static void testEmptyAndNullLongArray() { + ourDescription = "Check empty and null array"; + Arrays.sort(new long[] {}); + Arrays.sort(new long[] {}, 0, 0); + + try { + Arrays.sort((long[]) null); + } catch (NullPointerException expected) { + try { + Arrays.sort((long[]) null, 0, 0); + } catch (NullPointerException expected2) { + return; + } + failed("Arrays.sort(long[],fromIndex,toIndex) shouldn't " + + "catch null array"); + } + failed("Arrays.sort(long[]) shouldn't catch null array"); + } + + private static void testEmptyAndNullShortArray() { + ourDescription = "Check empty and null array"; + Arrays.sort(new short[] {}); + Arrays.sort(new short[] {}, 0, 0); + + try { + Arrays.sort((short[]) null); + } catch (NullPointerException expected) { + try { + Arrays.sort((short[]) null, 0, 0); + } catch (NullPointerException expected2) { + return; + } + failed("Arrays.sort(short[],fromIndex,toIndex) shouldn't " + + "catch null array"); + } + failed("Arrays.sort(short[]) shouldn't catch null array"); + } + + private static void testEmptyAndNullCharArray() { + ourDescription = "Check empty and null array"; + Arrays.sort(new char[] {}); + Arrays.sort(new char[] {}, 0, 0); - for (int m = 1; m < len / 2; m *= 2) { + try { + Arrays.sort((char[]) null); + } catch (NullPointerException expected) { + try { + Arrays.sort((char[]) null, 0, 0); + } catch (NullPointerException expected2) { + return; + } + failed("Arrays.sort(char[],fromIndex,toIndex) shouldn't " + + "catch null array"); + } + failed("Arrays.sort(char[]) shouldn't catch null array"); + } + + private static void testEmptyAndNullByteArray() { + ourDescription = "Check empty and null array"; + Arrays.sort(new byte[] {}); + Arrays.sort(new byte[] {}, 0, 0); + + try { + Arrays.sort((byte[]) null); + } catch (NullPointerException expected) { + try { + Arrays.sort((byte[]) null, 0, 0); + } catch (NullPointerException expected2) { + return; + } + failed("Arrays.sort(byte[],fromIndex,toIndex) shouldn't " + + "catch null array"); + } + failed("Arrays.sort(byte[]) shouldn't catch null array"); + } + + private static void testEmptyAndNullFloatArray() { + ourDescription = "Check empty and null array"; + Arrays.sort(new float[] {}); + Arrays.sort(new float[] {}, 0, 0); + + try { + Arrays.sort((float[]) null); + } catch (NullPointerException expected) { + try { + Arrays.sort((float[]) null, 0, 0); + } catch (NullPointerException expected2) { + return; + } + failed("Arrays.sort(float[],fromIndex,toIndex) shouldn't " + + "catch null array"); + } + failed("Arrays.sort(float[]) shouldn't catch null array"); + } + + private static void testEmptyAndNullDoubleArray() { + ourDescription = "Check empty and null array"; + Arrays.sort(new double[] {}); + Arrays.sort(new double[] {}, 0, 0); + + try { + Arrays.sort((double[]) null); + } catch (NullPointerException expected) { + try { + Arrays.sort((double[]) null, 0, 0); + } catch (NullPointerException expected2) { + return; + } + failed("Arrays.sort(double[],fromIndex,toIndex) shouldn't " + + "catch null array"); + } + failed("Arrays.sort(double[]) shouldn't catch null array"); + } + + private static void testAndCheckSubArray(int length, long random) { + ourDescription = "Check sorting of subarray"; + int[] golden = new int[length]; + boolean newLine = false; + + for (int m = 1; m < length / 2; m *= 2) { + newLine = true; int fromIndex = m; - int toIndex = len - m; + int toIndex = length - m; prepareSubArray(golden, fromIndex, toIndex, m); int[] test = golden.clone(); for (TypeConverter converter : TypeConverter.values()) { - out.println("Test #6: " + converter + - " len = " + len + ", m = " + m); + out.println("Test 'subarray': " + converter + + " length = " + length + ", m = " + m); Object convertedGolden = converter.convert(golden); Object convertedTest = converter.convert(test); - - // outArr(test); + // outArray(test); sortSubArray(convertedTest, fromIndex, toIndex); - // outArr(test); + // outArray(test); checkSubArray(convertedTest, fromIndex, toIndex, m); } } + if (newLine) { + out.println(); + } + } + + private static void testAndCheckRange(int length, long random) { + ourDescription = "Check range check"; + int[] golden = new int[length]; + + for (int m = 1; m < 2 * length; m *= 2) { + for (int i = 1; i <= length; i++) { + golden[i - 1] = i % m + m % i; + } + for (TypeConverter converter : TypeConverter.values()) { + out.println("Test 'range': " + converter + + ", length = " + length + ", m = " + m); + Object convertedGolden = converter.convert(golden); + checkRange(convertedGolden, m); + } + } out.println(); } - private static void testAndCheckRange(int len, long random) { - int[] golden = new int[len]; + private static void testStable(int length, long random) { + ourDescription = "Check if sorting is stable"; + Pair[] a = build(length); - for (int m = 1; m < 2 * len; m *= 2) { - for (int i = 1; i <= len; i++) { - golden[i - 1] = i % m + m % i; + out.println("Test 'stable': " + "random = " + random + + ", length = " + length); + Arrays.sort(a); + checkSorted(a); + checkStable(a); + } + + private static void checkSorted(Pair[] a) { + for (int i = 0; i < a.length - 1; i++) { + if (a[i].getKey() > a[i + 1].getKey()) { + failed(i, "" + a[i].getKey(), "" + a[i + 1].getKey()); } - for (TypeConverter converter : TypeConverter.values()) { - out.println("Test #5: " + converter + - ", len = " + len + ", m = " + m); - Object convertedGolden = converter.convert(golden); - sortRange(convertedGolden, m); - sortEmpty(convertedGolden); + } + } + + private static void checkStable(Pair[] a) { + for (int i = 0; i < a.length / 4; ) { + int key1 = a[i].getKey(); + int value1 = a[i++].getValue(); + int key2 = a[i].getKey(); + int value2 = a[i++].getValue(); + int key3 = a[i].getKey(); + int value3 = a[i++].getValue(); + int key4 = a[i].getKey(); + int value4 = a[i++].getValue(); + + if (!(key1 == key2 && key2 == key3 && key3 == key4)) { + failed("On position " + i + " must keys are different " + + key1 + ", " + key2 + ", " + key3 + ", " + key4); + } + if (!(value1 < value2 && value2 < value3 && value3 < value4)) { + failed("Sorting is not stable at position " + i + + ". Second values have been changed: " + value1 + ", " + + value2 + ", " + value3 + ", " + value4); } } - out.println(); + } + + private static Pair[] build(int length) { + Pair[] a = new Pair[length * 4]; + + for (int i = 0; i < a.length; ) { + int key = ourRandom.nextInt(); + a[i++] = new Pair(key, 1); + a[i++] = new Pair(key, 2); + a[i++] = new Pair(key, 3); + a[i++] = new Pair(key, 4); + } + return a; } - private static void testAndCheckWithCheckSum(int len, long random) { - int[] golden = new int[len]; + private static final class Pair implements Comparable { + Pair(int key, int value) { + myKey = key; + myValue = value; + } + + int getKey() { + return myKey; + } + + int getValue() { + return myValue; + } - for (int m = 1; m < 2 * len; m *= 2) { + public int compareTo(Pair pair) { + if (myKey < pair.myKey) { + return -1; + } + if (myKey > pair.myKey) { + return 1; + } + return 0; + } + + @Override + public String toString() { + return "(" + myKey + ", " + myValue + ")"; + } + + private int myKey; + private int myValue; + } + + private static void testAndCheckWithCheckSum(int length, long random) { + ourDescription = "Check sorting with check sum"; + int[] golden = new int[length]; + + for (int m = 1; m < 2 * length; m *= 2) { for (UnsortedBuilder builder : UnsortedBuilder.values()) { builder.build(golden, m); int[] test = golden.clone(); for (TypeConverter converter : TypeConverter.values()) { - out.println("Test #1: " + converter + " " + builder + - "random = " + random + ", len = " + len + - ", m = " + m); + out.println("Test 'check sum': " + converter + " " + + builder + "random = " + random + ", length = " + + length + ", m = " + m); Object convertedGolden = converter.convert(golden); Object convertedTest = converter.convert(test); sort(convertedTest); @@ -168,11 +408,12 @@ out.println(); } - private static void testAndCheckWithScrambling(int len, long random) { - int[] golden = new int[len]; + private static void testAndCheckWithScrambling(int length, long random) { + ourDescription = "Check sorting with scrambling"; + int[] golden = new int[length]; for (int m = 1; m <= 7; m++) { - if (m > len) { + if (m > length) { break; } for (SortedBuilder builder : SortedBuilder.values()) { @@ -181,9 +422,9 @@ scramble(test); for (TypeConverter converter : TypeConverter.values()) { - out.println("Test #2: " + converter + " " + builder + - "random = " + random + ", len = " + len + - ", m = " + m); + out.println("Test 'scrambling': " + converter + " " + + builder + "random = " + random + ", length = " + + length + ", m = " + m); Object convertedGolden = converter.convert(golden); Object convertedTest = converter.convert(test); sort(convertedTest); @@ -194,8 +435,9 @@ out.println(); } - private static void testAndCheckFloat(int len, long random) { - float[] golden = new float[len]; + private static void testAndCheckFloat(int length, long random) { + ourDescription = "Check float sorting"; + float[] golden = new float[length]; final int MAX = 10; boolean newLine = false; @@ -204,22 +446,23 @@ for (int z = 0; z <= MAX; z++) { for (int n = 0; n <= MAX; n++) { for (int p = 0; p <= MAX; p++) { - if (a + g + z + n + p > len) { + if (a + g + z + n + p > length) { continue; } - if (a + g + z + n + p < len) { + if (a + g + z + n + p < length) { continue; } for (FloatBuilder builder : FloatBuilder.values()) { - out.println("Test #3: random = " + random + - ", len = " + len + ", a = " + a + ", g = " + g + - ", z = " + z + ", n = " + n + ", p = " + p); + out.println("Test 'float': random = " + random + + ", length = " + length + ", a = " + a + + ", g = " + g + ", z = " + z + ", n = " + n + + ", p = " + p); builder.build(golden, a, g, z, n, p); float[] test = golden.clone(); scramble(test); - // outArr(test); + // outArray(test); sort(test); - // outArr(test); + // outArray(test); compare(test, golden, a, n, g); } newLine = true; @@ -233,8 +476,9 @@ } } - private static void testAndCheckDouble(int len, long random) { - double[] golden = new double[len]; + private static void testAndCheckDouble(int length, long random) { + ourDescription = "Check double sorting"; + double[] golden = new double[length]; final int MAX = 10; boolean newLine = false; @@ -243,22 +487,22 @@ for (int z = 0; z <= MAX; z++) { for (int n = 0; n <= MAX; n++) { for (int p = 0; p <= MAX; p++) { - if (a + g + z + n + p > len) { + if (a + g + z + n + p > length) { continue; } - if (a + g + z + n + p < len) { + if (a + g + z + n + p < length) { continue; } for (DoubleBuilder builder : DoubleBuilder.values()) { - out.println("Test #4: random = " + random + - ", len = " + len + ", a = " + a + ", g = " + g + - ", z = " + z + ", n = " + n + ", p = " + p); + out.println("Test 'double': random = " + random + + ", length = " + length + ", a = " + a + ", g = " + + g + ", z = " + z + ", n = " + n + ", p = " + p); builder.build(golden, a, g, z, n, p); double[] test = golden.clone(); scramble(test); - // outArr(test); + // outArray(test); sort(test); - // outArr(test); + // outArray(test); compare(test, golden, a, n, g); } newLine = true; @@ -276,37 +520,29 @@ for (int i = 0; i < fromIndex; i++) { a[i] = 0xBABA; } - for (int i = fromIndex; i < toIndex; i++) { a[i] = -i + m; } - for (int i = toIndex; i < a.length; i++) { a[i] = 0xDEDA; } } private static void scramble(int[] a) { - int length = a.length; - - for (int i = 0; i < length * 7; i++) { - swap(a, ourRandom.nextInt(length), ourRandom.nextInt(length)); + for (int i = 0; i < a.length * 7; i++) { + swap(a, ourRandom.nextInt(a.length), ourRandom.nextInt(a.length)); } } private static void scramble(float[] a) { - int length = a.length; - - for (int i = 0; i < length * 7; i++) { - swap(a, ourRandom.nextInt(length), ourRandom.nextInt(length)); + for (int i = 0; i < a.length * 7; i++) { + swap(a, ourRandom.nextInt(a.length), ourRandom.nextInt(a.length)); } } private static void scramble(double[] a) { - int length = a.length; - - for (int i = 0; i < length * 7; i++) { - swap(a, ourRandom.nextInt(length), ourRandom.nextInt(length)); + for (int i = 0; i < a.length * 7; i++) { + swap(a, ourRandom.nextInt(a.length), ourRandom.nextInt(a.length)); } } @@ -393,6 +629,16 @@ } return b; } + }, + INTEGER { + Object convert(int[] a) { + Integer[] b = new Integer[a.length]; + + for (int i = 0; i < a.length; i++) { + b[i] = new Integer(a[i]); + } + return b; + } }; abstract Object convert(int[] a); @@ -691,6 +937,8 @@ compare((float[]) test, (float[]) golden); } else if (test instanceof double[]) { compare((double[]) test, (double[]) golden); + } else if (test instanceof Integer[]) { + compare((Integer[]) test, (Integer[]) golden); } else { failed("Unknow type of array: " + test + " of class " + test.getClass().getName()); @@ -703,13 +951,13 @@ } private static void failed(String message) { - err.format("\n*** FAILED: %s\n\n", message); + err.format("\n*** TEST FAILED - %s\n\n%s\n\n", ourDescription, message); throw new RuntimeException("Test failed - see log file for details"); } private static void failed(int index, String value1, String value2) { - failed("Array is not sorted at " + index + "-th position: " + value1 + - " and " + value2); + failed("Array is not sorted at " + index + "-th position: " + + value1 + " and " + value2); } private static void checkSorted(Object object) { @@ -727,12 +975,22 @@ checkSorted((float[]) object); } else if (object instanceof double[]) { checkSorted((double[]) object); + } else if (object instanceof Integer[]) { + checkSorted((Integer[]) object); } else { failed("Unknow type of array: " + object + " of class " + object.getClass().getName()); } } + private static void compare(Integer[] a, Integer[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i].intValue() != b[i].intValue()) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + private static void compare(int[] a, int[] b) { for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) { @@ -789,6 +1047,14 @@ } } + private static void checkSorted(Integer[] a) { + for (int i = 0; i < a.length - 1; i++) { + if (a[i].intValue() > a[i + 1].intValue()) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + } + private static void checkSorted(int[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { @@ -847,7 +1113,7 @@ private static void checkCheckSum(Object test, Object golden) { if (checkSum(test) != checkSum(golden)) { - failed("Original and sorted arrays seems not identical"); + failed("It seems that original and sorted arrays are not identical"); } } @@ -866,6 +1132,8 @@ return checkSum((float[]) object); } else if (object instanceof double[]) { return checkSum((double[]) object); + } else if (object instanceof Integer[]) { + return checkSum((Integer[]) object); } else { failed("Unknow type of array: " + object + " of class " + object.getClass().getName()); @@ -873,6 +1141,15 @@ } } + private static int checkSum(Integer[] a) { + int checkXorSum = 0; + + for (Integer e : a) { + checkXorSum ^= e.intValue(); + } + return checkXorSum; + } + private static int checkSum(int[] a) { int checkXorSum = 0; @@ -951,6 +1228,8 @@ Arrays.sort((float[]) object); } else if (object instanceof double[]) { Arrays.sort((double[]) object); + } else if (object instanceof Integer[]) { + Arrays.sort((Integer[]) object); } else { failed("Unknow type of array: " + object + " of class " + object.getClass().getName()); @@ -972,6 +1251,8 @@ Arrays.sort((float[]) object, fromIndex, toIndex); } else if (object instanceof double[]) { Arrays.sort((double[]) object, fromIndex, toIndex); + } else if (object instanceof Integer[]) { + Arrays.sort((Integer[]) object, fromIndex, toIndex); } else { failed("Unknow type of array: " + object + " of class " + object.getClass().getName()); @@ -993,12 +1274,36 @@ checkSubArray((float[]) object, fromIndex, toIndex, m); } else if (object instanceof double[]) { checkSubArray((double[]) object, fromIndex, toIndex, m); + } else if (object instanceof Integer[]) { + checkSubArray((Integer[]) object, fromIndex, toIndex, m); } else { failed("Unknow type of array: " + object + " of class " + object.getClass().getName()); } } + private static void checkSubArray(Integer[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i].intValue() != 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i].intValue() > a[i + 1].intValue()) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i].intValue() != 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) { for (int i = 0; i < fromIndex; i++) { if (a[i] != 0xBABA) { @@ -1153,49 +1458,30 @@ } } - private static void sortRange(Object object, int m) { + private static void checkRange(Object object, int m) { if (object instanceof int[]) { - sortRange((int[]) object, m); + checkRange((int[]) object, m); } else if (object instanceof long[]) { - sortRange((long[]) object, m); + checkRange((long[]) object, m); } else if (object instanceof short[]) { - sortRange((short[]) object, m); + checkRange((short[]) object, m); } else if (object instanceof byte[]) { - sortRange((byte[]) object, m); + checkRange((byte[]) object, m); } else if (object instanceof char[]) { - sortRange((char[]) object, m); + checkRange((char[]) object, m); } else if (object instanceof float[]) { - sortRange((float[]) object, m); + checkRange((float[]) object, m); } else if (object instanceof double[]) { - sortRange((double[]) object, m); + checkRange((double[]) object, m); + } else if (object instanceof Integer[]) { + checkRange((Integer[]) object, m); } else { failed("Unknow type of array: " + object + " of class " + object.getClass().getName()); } } - private static void sortEmpty(Object object) { - if (object instanceof int[]) { - Arrays.sort(new int [] {}); - } else if (object instanceof long[]) { - Arrays.sort(new long [] {}); - } else if (object instanceof short[]) { - Arrays.sort(new short [] {}); - } else if (object instanceof byte[]) { - Arrays.sort(new byte [] {}); - } else if (object instanceof char[]) { - Arrays.sort(new char [] {}); - } else if (object instanceof float[]) { - Arrays.sort(new float [] {}); - } else if (object instanceof double[]) { - Arrays.sort(new double [] {}); - } else { - failed("Unknow type of array: " + object + " of class " + - object.getClass().getName()); - } - } - - private static void sortRange(int[] a, int m) { + private static void checkRange(Integer[] a, int m) { try { Arrays.sort(a, m + 1, m); @@ -1224,7 +1510,36 @@ } } - private static void sortRange(long[] a, int m) { + private static void checkRange(int[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void checkRange(long[] a, int m) { try { Arrays.sort(a, m + 1, m); @@ -1253,7 +1568,7 @@ } } - private static void sortRange(byte[] a, int m) { + private static void checkRange(byte[] a, int m) { try { Arrays.sort(a, m + 1, m); @@ -1282,7 +1597,7 @@ } } - private static void sortRange(short[] a, int m) { + private static void checkRange(short[] a, int m) { try { Arrays.sort(a, m + 1, m); @@ -1311,7 +1626,7 @@ } } - private static void sortRange(char[] a, int m) { + private static void checkRange(char[] a, int m) { try { Arrays.sort(a, m + 1, m); @@ -1340,7 +1655,7 @@ } } - private static void sortRange(float[] a, int m) { + private static void checkRange(float[] a, int m) { try { Arrays.sort(a, m + 1, m); @@ -1369,7 +1684,7 @@ } } - private static void sortRange(double[] a, int m) { + private static void checkRange(double[] a, int m) { try { Arrays.sort(a, m + 1, m); @@ -1410,31 +1725,36 @@ ourSecond = 0; } - private static void outArr(int[] a) { + private static void outArray(Object[] a) { + for (int i = 0; i < a.length; i++) { + out.print(a[i] + " "); + } + out.println(); + } + + private static void outArray(int[] a) { for (int i = 0; i < a.length; i++) { out.print(a[i] + " "); } out.println(); - out.println(); } - private static void outArr(float[] a) { + private static void outArray(float[] a) { for (int i = 0; i < a.length; i++) { out.print(a[i] + " "); } out.println(); - out.println(); } - private static void outArr(double[] a) { + private static void outArray(double[] a) { for (int i = 0; i < a.length; i++) { out.print(a[i] + " "); } out.println(); - out.println(); } private static int ourFirst; private static int ourSecond; private static Random ourRandom; + private static String ourDescription; } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/util/logging/AnonLoggerWeakRefLeak.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/logging/AnonLoggerWeakRefLeak.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.logging.*; + +public class AnonLoggerWeakRefLeak { + public static int DEFAULT_LOOP_TIME = 60; // time is in seconds + + public static void main(String[] args) { + int loop_time = 0; + int max_loop_time = DEFAULT_LOOP_TIME; + + if (args.length == 0) { + System.out.println("INFO: using default time of " + + max_loop_time + " seconds."); + } else { + try { + max_loop_time = Integer.parseInt(args[0]); + } catch (NumberFormatException nfe) { + System.err.println("Error: '" + args[0] + + "': is not a valid seconds value."); + System.err.println("Usage: AnonLoggerWeakRefLeak [seconds]"); + System.exit(1); + } + } + + long count = 0; + long now = 0; + long startTime = System.currentTimeMillis(); + + while (now < (startTime + (max_loop_time * 1000))) { + if ((count % 1000) == 0) { + // Print initial call count to let caller know that + // we're up and running and then periodically + System.out.println("INFO: call count = " + count); + } + + for (int i = 0; i < 100; i++) { + // this Logger call is leaking a WeakReference in Logger.kids + java.util.logging.Logger.getAnonymousLogger(); + count++; + } + + try { + // delay for 1/10 of a second to avoid CPU saturation + Thread.sleep(100); + } catch (InterruptedException ie) { + // ignore any exceptions + } + + now = System.currentTimeMillis(); + } + + System.out.println("INFO: final loop count = " + count); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/util/logging/AnonLoggerWeakRefLeak.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/logging/AnonLoggerWeakRefLeak.sh Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,247 @@ +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 6942989 +# @ignore until 6964018 is fixed +# @summary Check for WeakReference leak in anonymous Logger objects +# @author Daniel D. Daugherty +# +# @run build AnonLoggerWeakRefLeak +# @run shell/timeout=180 AnonLoggerWeakRefLeak.sh + +# The timeout is: 2 minutes for infrastructure and 1 minute for the test +# + +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +JAVA="${TESTJAVA}"/bin/java +JMAP="${TESTJAVA}"/bin/jmap +JPS="${TESTJAVA}"/bin/jps + +set -eu + +TEST_NAME="AnonLoggerWeakRefLeak" +TARGET_CLASS="java\.lang\.ref\.WeakReference" + +is_cygwin=false +is_mks=false +is_windows=false + +case `uname -s` in +CYGWIN*) + is_cygwin=true + is_windows=true + ;; +Windows_*) + is_mks=true + is_windows=true + ;; +*) + ;; +esac + + +# wrapper for grep +# +grep_cmd() { + set +e + if $is_windows; then + # need dos2unix to get rid of CTRL-M chars from java output + dos2unix | grep "$@" + status="$?" + else + grep "$@" + status="$?" + fi + set -e +} + + +# MAIN begins here +# + +seconds= +if [ "$#" -gt 0 ]; then + seconds="$1" +fi + +# see if this version of jmap supports the '-histo:live' option +jmap_option="-histo:live" +set +e +"${JMAP}" "$jmap_option" 0 > "$TEST_NAME.jmap" 2>&1 +grep '^Usage: ' "$TEST_NAME.jmap" > /dev/null 2>&1 +status="$?" +set -e +if [ "$status" = 0 ]; then + echo "INFO: switching jmap option from '$jmap_option'\c" + jmap_option="-histo" + echo " to '$jmap_option'." +fi + +"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" \ + "$TEST_NAME" $seconds > "$TEST_NAME.log" 2>&1 & +test_pid="$!" +echo "INFO: starting $TEST_NAME as pid = $test_pid" + +# wait for test program to get going +count=0 +while [ "$count" -lt 30 ]; do + sleep 2 + grep_cmd '^INFO: call count = 0$' < "$TEST_NAME.log" > /dev/null 2>&1 + if [ "$status" = 0 ]; then + break + fi + count=`expr $count + 1` +done + +if [ "$count" -ge 30 ]; then + echo "ERROR: $TEST_NAME failed to get going." >&2 + echo "INFO: killing $test_pid" + kill "$test_pid" + exit 1 +elif [ "$count" -gt 1 ]; then + echo "INFO: $TEST_NAME took $count loops to start." +fi + +if $is_cygwin; then + # We need the Windows pid for jmap and not the Cygwin pid. + # Note: '\t' works on Cygwin, but doesn't seem to work on Solaris. + jmap_pid=`"${JPS}"| grep_cmd "[ \t]$TEST_NAME$" | sed 's/[ \t].*//'` + if [ -z "$jmap_pid" ]; then + echo "FAIL: jps could not map Cygwin pid to Windows pid." >&2 + echo "INFO: killing $test_pid" + kill "$test_pid" + exit 2 + fi + echo "INFO: pid = $test_pid maps to Windows pid = $jmap_pid" +else + jmap_pid="$test_pid" +fi + +decreasing_cnt=0 +increasing_cnt=0 +loop_cnt=0 +prev_instance_cnt=0 + +while true; do + # Output format for 'jmap -histo' in JDK1.5.0: + # + # <#bytes> <#instances> + # + # Output format for 'jmap -histo:live': + # + # : <#instances> <#bytes> + # + set +e + "${JMAP}" "$jmap_option" "$jmap_pid" > "$TEST_NAME.jmap" 2>&1 + status="$?" + set -e + + if [ "$status" != 0 ]; then + echo "INFO: jmap exited with exit code = $status" + if [ "$loop_cnt" = 0 ]; then + echo "INFO: on the first iteration so no samples were taken." + echo "INFO: start of jmap output:" + cat "$TEST_NAME.jmap" + echo "INFO: end of jmap output." + echo "FAIL: jmap is unable to take any samples." >&2 + echo "INFO: killing $test_pid" + kill "$test_pid" + exit 2 + fi + echo "INFO: The likely reason is that $TEST_NAME has finished running." + break + fi + + instance_cnt=`grep_cmd "[ ]$TARGET_CLASS$" \ + < "$TEST_NAME.jmap" \ + | sed ' + # strip leading whitespace; does nothing in JDK1.5.0 + s/^[ ][ ]*// + # strip <#bytes> in JDK1.5.0; does nothing otherwise + s/^[1-9][0-9]*[ ][ ]*// + # strip : field; does nothing in JDK1.5.0 + s/^[1-9][0-9]*:[ ][ ]*// + # strip field + s/[ ].*// + '` + if [ -z "$instance_cnt" ]; then + echo "INFO: instance count is unexpectedly empty" + if [ "$loop_cnt" = 0 ]; then + echo "INFO: on the first iteration so no sample was found." + echo "INFO: There is likely a problem with the sed filter." + echo "INFO: start of jmap output:" + cat "$TEST_NAME.jmap" + echo "INFO: end of jmap output." + echo "FAIL: cannot find the instance count value." >&2 + echo "INFO: killing $test_pid" + kill "$test_pid" + exit 2 + fi + else + echo "INFO: instance_cnt = $instance_cnt" + + if [ "$instance_cnt" -gt "$prev_instance_cnt" ]; then + increasing_cnt=`expr $increasing_cnt + 1` + else + decreasing_cnt=`expr $decreasing_cnt + 1` + fi + prev_instance_cnt="$instance_cnt" + fi + + # delay between samples + sleep 5 + + loop_cnt=`expr $loop_cnt + 1` +done + +echo "INFO: increasing_cnt = $increasing_cnt" +echo "INFO: decreasing_cnt = $decreasing_cnt" + +echo "INFO: The instance count of" `eval echo $TARGET_CLASS` "objects" +if [ "$decreasing_cnt" = 0 ]; then + echo "INFO: is always increasing." + echo "FAIL: This indicates that there is a memory leak." >&2 + exit 2 +fi + +echo "INFO: is both increasing and decreasing." +echo "PASS: This indicates that there is not a memory leak." +exit 0 diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/util/logging/LoggerWeakRefLeak.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/logging/LoggerWeakRefLeak.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.logging.*; + +public class LoggerWeakRefLeak { + // AnonLoggerWeakRefLeak checks for one weak reference leak. + // LoggerWeakRefLeak checks for two weak reference leaks so + // this test runs twice as long, by default. + public static int DEFAULT_LOOP_TIME = 120; // time is in seconds + + public static void main(String[] args) { + int loop_time = 0; + int max_loop_time = DEFAULT_LOOP_TIME; + + if (args.length == 0) { + System.out.println("INFO: using default time of " + + max_loop_time + " seconds."); + } else { + try { + max_loop_time = Integer.parseInt(args[0]); + } catch (NumberFormatException nfe) { + System.err.println("Error: '" + args[0] + + "': is not a valid seconds value."); + System.err.println("Usage: LoggerWeakRefLeak [seconds]"); + System.exit(1); + } + } + + long count = 0; + int loggerCount = 0; + long now = 0; + long startTime = System.currentTimeMillis(); + + while (now < (startTime + (max_loop_time * 1000))) { + if ((count % 1000) == 0) { + // Print initial call count to let caller know that + // we're up and running and then periodically + System.out.println("INFO: call count = " + count); + } + + for (int i = 0; i < 100; i++) { + // This Logger call is leaking two different WeakReferences: + // - one in LogManager.LogNode + // - one in Logger.kids + java.util.logging.Logger.getLogger("logger-" + loggerCount); + count++; + if (++loggerCount >= 25000) { + // Limit the Logger namespace used by the test so + // the weak refs in LogManager.loggers that are + // being properly managed don't skew the counts + // by too much. + loggerCount = 0; + } + } + + try { + // delay for 1/10 of a second to avoid CPU saturation + Thread.sleep(100); + } catch (InterruptedException ie) { + // ignore any exceptions + } + + now = System.currentTimeMillis(); + } + + System.out.println("INFO: final loop count = " + count); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/java/util/logging/LoggerWeakRefLeak.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/logging/LoggerWeakRefLeak.sh Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,247 @@ +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 6942989 +# @ignore until 6964018 is fixed +# @summary Check for WeakReference leak in Logger objects +# @author Daniel D. Daugherty +# +# @run build LoggerWeakRefLeak +# @run shell/timeout=240 LoggerWeakRefLeak.sh + +# The timeout is: 2 minutes for infrastructure and 1 minute for the test +# + +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +JAVA="${TESTJAVA}"/bin/java +JMAP="${TESTJAVA}"/bin/jmap +JPS="${TESTJAVA}"/bin/jps + +set -eu + +TEST_NAME="LoggerWeakRefLeak" +TARGET_CLASS="java\.lang\.ref\.WeakReference" + +is_cygwin=false +is_mks=false +is_windows=false + +case `uname -s` in +CYGWIN*) + is_cygwin=true + is_windows=true + ;; +Windows_*) + is_mks=true + is_windows=true + ;; +*) + ;; +esac + + +# wrapper for grep +# +grep_cmd() { + set +e + if $is_windows; then + # need dos2unix to get rid of CTRL-M chars from java output + dos2unix | grep "$@" + status="$?" + else + grep "$@" + status="$?" + fi + set -e +} + + +# MAIN begins here +# + +seconds= +if [ "$#" -gt 0 ]; then + seconds="$1" +fi + +# see if this version of jmap supports the '-histo:live' option +jmap_option="-histo:live" +set +e +"${JMAP}" "$jmap_option" 0 > "$TEST_NAME.jmap" 2>&1 +grep '^Usage: ' "$TEST_NAME.jmap" > /dev/null 2>&1 +status="$?" +set -e +if [ "$status" = 0 ]; then + echo "INFO: switching jmap option from '$jmap_option'\c" + jmap_option="-histo" + echo " to '$jmap_option'." +fi + +"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" \ + "$TEST_NAME" $seconds > "$TEST_NAME.log" 2>&1 & +test_pid="$!" +echo "INFO: starting $TEST_NAME as pid = $test_pid" + +# wait for test program to get going +count=0 +while [ "$count" -lt 30 ]; do + sleep 2 + grep_cmd '^INFO: call count = 0$' < "$TEST_NAME.log" > /dev/null 2>&1 + if [ "$status" = 0 ]; then + break + fi + count=`expr $count + 1` +done + +if [ "$count" -ge 30 ]; then + echo "ERROR: $TEST_NAME failed to get going." >&2 + echo "INFO: killing $test_pid" + kill "$test_pid" + exit 1 +elif [ "$count" -gt 1 ]; then + echo "INFO: $TEST_NAME took $count loops to start." +fi + +if $is_cygwin; then + # We need the Windows pid for jmap and not the Cygwin pid. + # Note: '\t' works on Cygwin, but doesn't seem to work on Solaris. + jmap_pid=`"${JPS}"| grep_cmd "[ \t]$TEST_NAME$" | sed 's/[ \t].*//'` + if [ -z "$jmap_pid" ]; then + echo "FAIL: jps could not map Cygwin pid to Windows pid." >&2 + echo "INFO: killing $test_pid" + kill "$test_pid" + exit 2 + fi + echo "INFO: pid = $test_pid maps to Windows pid = $jmap_pid" +else + jmap_pid="$test_pid" +fi + +decreasing_cnt=0 +increasing_cnt=0 +loop_cnt=0 +prev_instance_cnt=0 + +while true; do + # Output format for 'jmap -histo' in JDK1.5.0: + # + # <#bytes> <#instances> + # + # Output format for 'jmap -histo:live': + # + # : <#instances> <#bytes> + # + set +e + "${JMAP}" "$jmap_option" "$jmap_pid" > "$TEST_NAME.jmap" 2>&1 + status="$?" + set -e + + if [ "$status" != 0 ]; then + echo "INFO: jmap exited with exit code = $status" + if [ "$loop_cnt" = 0 ]; then + echo "INFO: on the first iteration so no samples were taken." + echo "INFO: start of jmap output:" + cat "$TEST_NAME.jmap" + echo "INFO: end of jmap output." + echo "FAIL: jmap is unable to take any samples." >&2 + echo "INFO: killing $test_pid" + kill "$test_pid" + exit 2 + fi + echo "INFO: The likely reason is that $TEST_NAME has finished running." + break + fi + + instance_cnt=`grep_cmd "[ ]$TARGET_CLASS$" \ + < "$TEST_NAME.jmap" \ + | sed ' + # strip leading whitespace; does nothing in JDK1.5.0 + s/^[ ][ ]*// + # strip <#bytes> in JDK1.5.0; does nothing otherwise + s/^[1-9][0-9]*[ ][ ]*// + # strip : field; does nothing in JDK1.5.0 + s/^[1-9][0-9]*:[ ][ ]*// + # strip field + s/[ ].*// + '` + if [ -z "$instance_cnt" ]; then + echo "INFO: instance count is unexpectedly empty" + if [ "$loop_cnt" = 0 ]; then + echo "INFO: on the first iteration so no sample was found." + echo "INFO: There is likely a problem with the sed filter." + echo "INFO: start of jmap output:" + cat "$TEST_NAME.jmap" + echo "INFO: end of jmap output." + echo "FAIL: cannot find the instance count value." >&2 + echo "INFO: killing $test_pid" + kill "$test_pid" + exit 2 + fi + else + echo "INFO: instance_cnt = $instance_cnt" + + if [ "$instance_cnt" -gt "$prev_instance_cnt" ]; then + increasing_cnt=`expr $increasing_cnt + 1` + else + decreasing_cnt=`expr $decreasing_cnt + 1` + fi + prev_instance_cnt="$instance_cnt" + fi + + # delay between samples + sleep 5 + + loop_cnt=`expr $loop_cnt + 1` +done + +echo "INFO: increasing_cnt = $increasing_cnt" +echo "INFO: decreasing_cnt = $decreasing_cnt" + +echo "INFO: The instance count of" `eval echo $TARGET_CLASS` "objects" +if [ "$decreasing_cnt" = 0 ]; then + echo "INFO: is always increasing." + echo "FAIL: This indicates that there is a memory leak." >&2 + exit 2 +fi + +echo "INFO: is both increasing and decreasing." +echo "PASS: This indicates that there is not a memory leak." +exit 0 diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/javax/swing/AbstractButton/6711682/bug6711682.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/AbstractButton/6711682/bug6711682.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 6711682 + @summary JCheckBox in JTable: checkbox doesn't alaways respond to the first mouse click + @author Alexander Potochkin + @run main bug6711682 +*/ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import javax.swing.event.CellEditorListener; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.EventObject; + +public class bug6711682 { + private static JCheckBox editorCb; + private static JCheckBox rendererCb; + private static JTable table; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(50); + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); + toolkit.realSync(); + Point l = table.getLocationOnScreen(); + int h = table.getRowHeight(); + for (int i = 0; i < 3; i++) { + robot.mouseMove(l.x + 5, l.y + 5 + i * h); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + } + // Without pressing F2 the last table's cell + // reported false value + // note that I can't press it inside the for loop + // because it doesn't reproduce the bug + robot.keyPress(KeyEvent.VK_F2); + robot.keyRelease(KeyEvent.VK_F2); + + for (int i = 0; i < 3; i++) { + if (!Boolean.TRUE.equals(table.getValueAt(i, 0))) { + throw new RuntimeException("Row #" + i + " checkbox is not selected"); + } + } + for (int i = 2; i >= 0; i--) { + robot.mouseMove(l.x + 5, l.y + 5 + i * h); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + } + robot.keyPress(KeyEvent.VK_F2); + robot.keyRelease(KeyEvent.VK_F2); + for (int i = 0; i < 3; i++) { + if (Boolean.TRUE.equals(table.getValueAt(i, 0))) { + throw new RuntimeException("Row #" + i + " checkbox is selected"); + } + } + } + + private static void createAndShowGUI() { + editorCb = new JCheckBox(); + rendererCb = new JCheckBox(); + JFrame f = new JFrame("Table with CheckBox"); + Container p = f.getContentPane(); + p.setLayout(new BorderLayout()); + table = new JTable(new Object[][]{{false}, {false}, {false}}, new Object[]{"CheckBox"}); + TableCellEditor editor = new TableCellEditor() { + int editedRow; + + public Component getTableCellEditorComponent(JTable table, + Object value, boolean isSelected, int row, int column) { + this.editedRow = row; + editorCb.setSelected(Boolean.TRUE.equals(value)); + editorCb.setBackground(UIManager.getColor("Table.selectionBackground")); + return editorCb; + } + + public void addCellEditorListener(CellEditorListener l) { + } + + public void cancelCellEditing() { + } + + public Object getCellEditorValue() { + return editorCb.isSelected(); + } + + public boolean isCellEditable(EventObject anEvent) { + return true; + } + + public void removeCellEditorListener(CellEditorListener l) { + } + + public boolean shouldSelectCell(EventObject anEvent) { + return true; + } + + public boolean stopCellEditing() { + table.getModel().setValueAt(editorCb.isSelected(), editedRow, 0); + return true; + } + }; + table.getColumnModel().getColumn(0).setCellEditor(editor); + + TableCellRenderer renderer = new TableCellRenderer() { + public Component getTableCellRendererComponent(JTable table, + Object value, boolean isSelected, boolean hasFocus, + int row, int column) { + rendererCb.setSelected(Boolean.TRUE.equals(value)); + return rendererCb; + } + }; + table.getColumnModel().getColumn(0).setCellRenderer(renderer); + + p.add(table, BorderLayout.CENTER); + + f.pack(); + f.setVisible(true); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/javax/swing/JFileChooser/6520101/bug6520101.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JFileChooser/6520101/bug6520101.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test @(#)bug6520101 + * @bug 6520101 + * @summary JFileChooser throws OOM in 1.4.2, 5.0u4 and 1.6.0 + * @author Praveen Gupta + * @run main/othervm/timeout=600 -Xmx8m -verify bug6520101 +*/ + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class bug6520101 implements Runnable { + + private static final int ATTEMPTS = 500; + private static final int INTERVAL = 100; + + private static final boolean ALWAYS_NEW_INSTANCE = false; + private static final boolean DO_GC_EACH_INTERVAL = false; + private static final boolean UPDATE_UI_EACH_INTERVAL = true; + private static final boolean AUTO_CLOSE_DIALOG = true; + + private static JFileChooser CHOOSER; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + + for (int i = 0; i < ATTEMPTS; i++) { + doAttempt(); + } + + System.out.println("Test passed successfully"); + } + + private static void doAttempt() throws InterruptedException { + if (ALWAYS_NEW_INSTANCE || (CHOOSER == null)) + CHOOSER = new JFileChooser("."); + + if (UPDATE_UI_EACH_INTERVAL) { + CHOOSER.updateUI(); + } + + if (AUTO_CLOSE_DIALOG) { + Thread t = new Thread(new bug6520101(CHOOSER)); + t.start(); + CHOOSER.showOpenDialog(null); + t.join(); + } else { + CHOOSER.showOpenDialog(null); + } + + if (DO_GC_EACH_INTERVAL) { + System.gc(); + } + } + + private final JFileChooser chooser; + + bug6520101(JFileChooser chooser) { + this.chooser = chooser; + } + + public void run() { + while (!this.chooser.isShowing()) { + try { + Thread.sleep(30); + } catch (InterruptedException exception) { + exception.printStackTrace(); + } + } + + Timer timer = new Timer(INTERVAL, new ActionListener() { + public void actionPerformed(ActionEvent e) { + chooser.cancelSelection(); + } + }); + + timer.setRepeats(false); + timer.start(); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/javax/swing/JInternalFrame/6725409/bug6725409.java --- a/jdk/test/javax/swing/JInternalFrame/6725409/bug6725409.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/javax/swing/JInternalFrame/6725409/bug6725409.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ new com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel()); } catch(UnsupportedLookAndFeelException e) { System.out.println("The test is for Windows LaF only"); - System.exit(0); + return; } final bug6725409 bug6725409 = new bug6725409(); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6495920 + * @summary Tests that if the JPopupMenu.setVisible method throws an exception, + interaction with GNOME is not crippled + * @author Sergey Malenkov + * @library ../.. + */ + +import sun.awt.AppContext; + +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.lang.reflect.Field; +import javax.swing.JFrame; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicPopupMenuUI; + +public class bug6495920 implements Thread.UncaughtExceptionHandler { + + public static void main(String[] args) throws Throwable { + SwingTest.start(bug6495920.class); + } + + private static Robot robot; + private final JPanel panel; + + public bug6495920(JFrame frame) { + JPopupMenu menu = new JPopupMenu() { + public void setVisible(boolean visible) { + super.setVisible(visible); + throw new AssertionError(visible ? "show popup" : "hide popup"); + } + }; + for (int i = 0; i < 10; i++) { + menu.add(new JMenuItem(String.valueOf(i))); + } + this.panel = new JPanel(); + this.panel.setComponentPopupMenu(menu); + frame.add(this.panel); + } + + public void firstShowPopup() throws Exception { + Point point = this.panel.getLocation(); + SwingUtilities.convertPointToScreen(point, this.panel); + + robot = new Robot(); // initialize shared static field first time + robot.mouseMove(point.x + 1, point.y + 1); + robot.mousePress(InputEvent.BUTTON3_MASK); + Thread.currentThread().setUncaughtExceptionHandler(this); + robot.mouseRelease(InputEvent.BUTTON3_MASK); // causes first AssertionError on EDT + } + + public void secondHidePopup() { + Point point = this.panel.getLocation(); + SwingUtilities.convertPointToScreen(point, this.panel); + + robot.mouseMove(point.x - 1, point.y - 1); + Thread.currentThread().setUncaughtExceptionHandler(this); + robot.mousePress(InputEvent.BUTTON1_MASK); // causes second AssertionError on EDT + robot.mouseRelease(InputEvent.BUTTON1_MASK); + } + + public void thirdValidate() throws Exception { + Field key = BasicPopupMenuUI.class.getDeclaredField("MOUSE_GRABBER_KEY"); + key.setAccessible(true); + + Object grabber = AppContext.getAppContext().get(key.get(null)); + if (grabber == null) { + throw new Exception("cannot find a mouse grabber in app's context"); + } + + Field field = grabber.getClass().getDeclaredField("grabbedWindow"); + field.setAccessible(true); + + Object window = field.get(grabber); + if (window != null) { + throw new Exception("interaction with GNOME is crippled"); + } + } + + public void uncaughtException(Thread thread, Throwable throwable) { + System.out.println(throwable); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/javax/swing/JTable/6777378/bug6777378.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JTable/6777378/bug6777378.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 6777378 + @summary NullPointerException in XPDefaultRenderer.paint() + @author Alexander Potochkin + @run main bug6777378 +*/ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.JTableHeader; +import javax.swing.plaf.metal.MetalLookAndFeel; +import java.awt.event.MouseEvent; +import java.awt.event.InputEvent; +import java.awt.*; + +public class bug6777378 { + private static JFrame frame; + private static JTableHeader header; + + public static void main(String[] args) throws Exception { + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + Robot robot = new Robot(); + robot.setAutoDelay(20); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + try { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + } catch (Exception e) { + e.printStackTrace(); + } + JTable table = new JTable(new AbstractTableModel() { + public int getRowCount() { + return 10; + } + + public int getColumnCount() { + return 10; + } + + public Object getValueAt(int rowIndex, int columnIndex) { + return "" + rowIndex + " " + columnIndex; + } + }); + + header = new JTableHeader(table.getColumnModel()); + header.setToolTipText("hello"); + + frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.add(header); + + frame.setSize(300, 300); + frame.setVisible(true); + } + }); + toolkit.realSync(); + Point point = header.getLocationOnScreen(); + robot.mouseMove(point.x + 20, point.y + 50); + robot.mouseMove(point.x + 30, point.y + 50); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/javax/swing/border/Test4129681.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/border/Test4129681.html Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,10 @@ + + +When applet starts, you'll see a checkbox and a label with a titled border. +Turn on the checkbox to disable the label. +The test passes if the title of the border is disabled as well as the label. + + + + + diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/javax/swing/border/Test4129681.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/border/Test4129681.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4129681 + * @summary Tests enabling/disabling of titled border's caption + * @author Sergey Malenkov + * @run applet/manual=yesno Test4129681.html + */ + +import java.awt.BorderLayout; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import javax.swing.BorderFactory; +import javax.swing.JApplet; +import javax.swing.JCheckBox; +import javax.swing.JLabel; + +public class Test4129681 extends JApplet implements ItemListener { + private JLabel label; + + @Override + public void init() { + JCheckBox check = new JCheckBox("disable"); + check.addItemListener(this); + + this.label = new JLabel("message"); + this.label.setBorder(BorderFactory.createTitledBorder("label")); + this.label.setEnabled(!check.isSelected()); + + add(BorderLayout.NORTH, check); + add(BorderLayout.CENTER, this.label); + } + + public void itemStateChanged(ItemEvent event) { + this.label.setEnabled(ItemEvent.DESELECTED == event.getStateChange()); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/javax/swing/border/Test4760089.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/border/Test4760089.html Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,10 @@ + + +When applet starts, you'll see a panel with a compound titled border. +If one of its titles is overstriken with the border's line then test fails. +Otherwise test passes. + + + + + diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/javax/swing/border/Test4760089.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/border/Test4760089.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4760089 + * @summary Tests that titled border do not paint inner titled border over its caption + * @author Sergey Malenkov + * @run applet/manual=yesno Test4760089.html + */ + +import javax.swing.JApplet; +import javax.swing.JPanel; +import javax.swing.border.Border; +import javax.swing.border.EtchedBorder; +import javax.swing.border.TitledBorder; + +public class Test4760089 extends JApplet { + @Override + public void init() { + Border border = new EtchedBorder(); + border = new TitledBorder(border, "LEFT", TitledBorder.LEFT, TitledBorder.TOP); + border = new TitledBorder(border, "RIGHT", TitledBorder.RIGHT, TitledBorder.TOP); + + JPanel panel = new JPanel(); + panel.setBorder(border); + getContentPane().add(panel); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/sun/nio/ch/Basic.java --- a/jdk/test/sun/nio/ch/Basic.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/sun/nio/ch/Basic.java Wed Jul 05 17:18:12 2017 +0200 @@ -32,5 +32,7 @@ public class Basic { public static void main(String[] args) throws Exception { Pipe p = Pipe.open(); + p.source().close(); + p.sink().close(); } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/sun/nio/ch/TempBuffer.java --- a/jdk/test/sun/nio/ch/TempBuffer.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/sun/nio/ch/TempBuffer.java Wed Jul 05 17:18:12 2017 +0200 @@ -54,8 +54,12 @@ blah.deleteOnExit(); TempBuffer.initTestFile(blah); RandomAccessFile raf = new RandomAccessFile(blah, "rw"); - FileChannel fs = raf.getChannel(); - fs.transferTo(0, SIZE, Channels.newChannel(out)); + FileChannel fc = raf.getChannel(); + try { + fc.transferTo(0, SIZE, Channels.newChannel(out)); + } finally { + fc.close(); + } out.flush(); } catch (IOException ioe) { throw new RuntimeException(ioe); @@ -69,10 +73,17 @@ File blah = File.createTempFile("blah2", null); blah.deleteOnExit(); RandomAccessFile raf = new RandomAccessFile(blah, "rw"); - FileChannel fs = raf.getChannel(); - raf.setLength(SIZE); - fs.transferFrom(Channels.newChannel(in), 0, SIZE); - fs.close(); + FileChannel fc = raf.getChannel(); + try { + raf.setLength(SIZE); + fc.transferFrom(Channels.newChannel(in), 0, SIZE); + } finally { + fc.close(); + } + + sourceChannel.close(); + sinkChannel.close(); + blah.delete(); } private static void initTestFile(File blah) throws IOException { diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/sun/nio/cs/FindDecoderBugs.java --- a/jdk/test/sun/nio/cs/FindDecoderBugs.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/sun/nio/cs/FindDecoderBugs.java Wed Jul 05 17:18:12 2017 +0200 @@ -298,7 +298,7 @@ void testRandomly(byte[] prefix, int n) { int len = prefix.length; byte[] ia = Arrays.copyOf(prefix, len + n); - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 5000; i++) { for (int j = 0; j < n; j++) ia[len + j] = randomByte(); test(ia); @@ -435,6 +435,9 @@ static void equal(Object x, Object y) { if (x == null ? y == null : x.equals(y)) pass(); else fail(x + " not equal to " + y);} + static void equal(int x, int y) { + if (x == y) pass(); + else fail(x + " not equal to " + y);} public static void main(String[] args) throws Throwable { try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/sun/nio/cs/ReadZero.java --- a/jdk/test/sun/nio/cs/ReadZero.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/sun/nio/cs/ReadZero.java Wed Jul 05 17:18:12 2017 +0200 @@ -43,15 +43,18 @@ return 0; } }; - - is.read(new byte[1], 0, 1); // ok - InputStreamReader isr = new InputStreamReader(is); + try { + is.read(new byte[1], 0, 1); // ok + InputStreamReader isr = new InputStreamReader(is); - try { - int res = isr.read(new char[1], 0, 1); - } catch (IOException x) { - System.out.println("IOException caught"); - return; + try { + int res = isr.read(new char[1], 0, 1); + } catch (IOException x) { + System.out.println("IOException caught"); + return; + } + } finally { + is.close(); } throw new RuntimeException("IOException not thrown"); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/sun/nio/cs/Test4206507.java --- a/jdk/test/sun/nio/cs/Test4206507.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/sun/nio/cs/Test4206507.java Wed Jul 05 17:18:12 2017 +0200 @@ -32,7 +32,12 @@ public class Test4206507 { public static void main(String[] args) throws UnsupportedEncodingException { - Locale.setDefault(new Locale("tr", "TR")); - byte[] b = "".getBytes("ISO8859-9"); + Locale l = Locale.getDefault(); + try { + Locale.setDefault(new Locale("tr", "TR")); + byte[] b = "".getBytes("ISO8859-9"); + } finally { + Locale.setDefault(l); + } } } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/sun/nio/cs/TestStringCoding.java --- a/jdk/test/sun/nio/cs/TestStringCoding.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/sun/nio/cs/TestStringCoding.java Wed Jul 05 17:18:12 2017 +0200 @@ -26,7 +26,7 @@ /* @test @bug 6636323 6636319 @summary Test if StringCoding and NIO result have the same de/encoding result - * @run main/timeout=2000 TestStringCoding + * @run main/othervm/timeout=2000 TestStringCoding */ import java.util.*; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/sun/nio/cs/TestX11CNS.java --- a/jdk/test/sun/nio/cs/TestX11CNS.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/sun/nio/cs/TestX11CNS.java Wed Jul 05 17:18:12 2017 +0200 @@ -94,6 +94,8 @@ } static void compare(Charset newCS, Charset oldCS) throws Exception { + if (newCS == null) + return; // does not exist on this platform char[] cc = getChars(newCS, oldCS); System.out.printf(" Diff <%s> <%s>...%n", newCS.name(), oldCS.name()); @@ -120,14 +122,22 @@ } } + private static Charset getCharset(String czName) + throws Exception { + try { + return (Charset)Class.forName(czName).newInstance(); + } catch (ClassNotFoundException e){} + return null; // does not exist + } + public static void main(String[] args) throws Exception { - compare(new sun.awt.motif.X11CNS11643P1(), + compare(getCharset("sun.awt.motif.X11CNS11643P1"), new X11CNS11643P1()); - compare(new sun.awt.motif.X11CNS11643P2(), + compare(getCharset("sun.awt.motif.X11CNS11643P2"), new X11CNS11643P2()); - compare(new sun.awt.motif.X11CNS11643P3(), + compare(getCharset("sun.awt.motif.X11CNS11643P3"), new X11CNS11643P3()); } diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/sun/security/krb5/auto/SSL.java --- a/jdk/test/sun/security/krb5/auto/SSL.java Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/sun/security/krb5/auto/SSL.java Wed Jul 05 17:18:12 2017 +0200 @@ -25,6 +25,16 @@ * @test * @bug 6894643 6913636 * @summary Test JSSE Kerberos ciphersuite + * @run main SSL TLS_KRB5_WITH_RC4_128_SHA + * @run main SSL TLS_KRB5_WITH_RC4_128_MD5 + * @run main SSL TLS_KRB5_WITH_3DES_EDE_CBC_SHA + * @run main SSL TLS_KRB5_WITH_3DES_EDE_CBC_MD5 + * @run main SSL TLS_KRB5_WITH_DES_CBC_SHA + * @run main SSL TLS_KRB5_WITH_DES_CBC_MD5 + * @run main SSL TLS_KRB5_EXPORT_WITH_RC4_40_SHA + * @run main SSL TLS_KRB5_EXPORT_WITH_RC4_40_MD5 + * @run main SSL TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA + * @run main SSL TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 */ import java.io.*; import java.net.InetAddress; @@ -37,7 +47,7 @@ public class SSL { - private static final String KRB5_CIPHER = "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"; + private static String krb5Cipher; private static final int LOOP_LIMIT = 1; private static int loopCount = 0; private static volatile String server; @@ -45,6 +55,8 @@ public static void main(String[] args) throws Exception { + krb5Cipher = args[0]; + KDC kdc = KDC.create(OneKDC.REALM); // Run this after KDC, so our own DNS service can be started try { @@ -117,7 +129,7 @@ SSLSocket sslSocket = (SSLSocket) sslsf.createSocket(server, port); // Enable only a KRB5 cipher suite. - String enabledSuites[] = {KRB5_CIPHER}; + String enabledSuites[] = {krb5Cipher}; sslSocket.setEnabledCipherSuites(enabledSuites); // Should check for exception if enabledSuites is not supported @@ -155,7 +167,7 @@ port = sslServerSocket.getLocalPort(); // Enable only a KRB5 cipher suite. - String enabledSuites[] = {KRB5_CIPHER}; + String enabledSuites[] = {krb5Cipher}; sslServerSocket.setEnabledCipherSuites(enabledSuites); // Should check for exception if enabledSuites is not supported diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/sun/security/krb5/etype/ETypeOrder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/krb5/etype/ETypeOrder.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 6844907 + * @summary krb5 etype order should be from strong to weak + */ + +import sun.security.krb5.internal.crypto.EType; + +public class ETypeOrder { + public static void main(String[] args) throws Exception { + + // File does not exist, so that the system-default one won't be used + System.setProperty("java.security.krb5.conf", "no_such_file"); + int[] etypes = EType.getBuiltInDefaults(); + + // Reference order, note that 2 is not implemented in Java + int correct[] = { 18, 17, 16, 23, 1, 3, 2 }; + + int match = 0; + loopi: for (int i=0; i -# -xarch=v9. Also, the settings for JINCLUDE, JAVAC, and JAVAH should -# come from the current build. The C compiler should be the one -# approved for the build. To be extra safe, the binaries should be -# generated on the oldest Solaris release supported by the current -# Java build. - -# Include directory in JRE or JDK install; e.g. -JINCLUDE=/java/re/jdk/1.4.1/latest/binaries/solaris-sparc/include - -# Path to javac executable; e.g. -JAVAC=/java/re/jdk/1.4.1/promoted/fcs/b21/binaries/solaris-sparc/bin/javac - -# Path to javah executable; e.g. -JAVAH=/java/re/jdk/1.4.1/promoted/fcs/b21/binaries/solaris-sparc/bin/javah - -# Path to C compiler; e.g. -CC=/java/devtools/sparc/SUNWspro/SC6.1/bin/cc - - -ARCH=`uname -p` - -# 32-bit Solaris Options -DM=32 -# Default architecture is fine for both sparc and x86 32-bit builds -OPTIONS= - -# 64-bit Solaris Options -#DM=64 -#OPTIONS=-xarch=v9 - - -all: libraryCaller.java libraryCaller.c - $(JAVAC) libraryCaller.java; \ - $(JAVAH) libraryCaller; \ - $(CC) -G -I$(JINCLUDE) -I$(JINCLUDE)/solaris -DRETURN_VALUE=0 \ - $(OPTIONS) libraryCaller.c \ - -o lib/$(ARCH)/lib$(DM)/liblibrary.so; \ - $(CC) -G -I$(JINCLUDE) -I$(JINCLUDE)/solaris -DRETURN_VALUE=$(DM)\ - $(OPTIONS) libraryCaller.c \ - -o lib/$(ARCH)/lib$(DM)/lib$(DM)/liblibrary.so; diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/tools/launcher/UnicodeTest.sh --- a/jdk/test/tools/launcher/UnicodeTest.sh Wed Jul 05 17:17:22 2017 +0200 +++ b/jdk/test/tools/launcher/UnicodeTest.sh Wed Jul 05 17:18:12 2017 +0200 @@ -54,7 +54,11 @@ echo "creating test source files" "$JAVAC" -d . "${TESTSRC}"/UnicodeTest.java -CLASS_NAME=`"$JAVA" UnicodeTest | sed -e 's@\\r@@g' ` +if [ "`uname -s | grep CYGWIN`" != "" ] ; then + CLASS_NAME=`"$JAVA" UnicodeTest | sed -e 's@\\r@@g' ` +else + CLASS_NAME=`"$JAVA" UnicodeTest` +fi if [ "$CLASS_NAME" = "" ] then diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/tools/launcher/VerifyExceptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/VerifyExceptions.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6856415 + * @summary Checks to ensure that proper exceptions are thrown by java + * @compile -XDignore.symbol.file VerifyExceptions.java TestHelper.java + * @run main VerifyExceptions + */ + + +import java.io.File; +import java.io.FileNotFoundException; + + +public class VerifyExceptions { + + static void test6856415() { + // No pkcs library on win-x64, so we bail out. + if (TestHelper.is64Bit && TestHelper.isWindows) { + return; + } + StringBuilder sb = new StringBuilder(); + sb.append("public static void main(String... args) {\n"); + sb.append("java.security.Provider p = new sun.security.pkcs11.SunPKCS11(args[0]);\n"); + sb.append("java.security.Security.insertProviderAt(p, 1);\n"); + sb.append("}"); + File testJar = new File("Foo.jar"); + testJar.delete(); + try { + TestHelper.createJar(testJar, sb.toString()); + } catch (FileNotFoundException fnfe) { + throw new RuntimeException(fnfe); + } + TestHelper.TestResult tr = TestHelper.doExec(TestHelper.javacCmd, + "-Djava.security.manager", "-jar", testJar.getName(), "foo.bak"); + tr.checkNegative(); + tr.contains("Exception in thread \"main\" java.security.AccessControlException: access denied (\"java.lang.RuntimePermission\" \"accessClassInPackage.sun.security.pkcs11\")\")"); + } + + public static void main(String... args) { + test6856415(); + } +} diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/tools/launcher/lib/i386/lib32/lib32/liblibrary.so Binary file jdk/test/tools/launcher/lib/i386/lib32/lib32/liblibrary.so has changed diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/tools/launcher/lib/i386/lib32/liblibrary.so Binary file jdk/test/tools/launcher/lib/i386/lib32/liblibrary.so has changed diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/tools/launcher/lib/sparc/lib32/lib32/liblibrary.so Binary file jdk/test/tools/launcher/lib/sparc/lib32/lib32/liblibrary.so has changed diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/tools/launcher/lib/sparc/lib32/liblibrary.so Binary file jdk/test/tools/launcher/lib/sparc/lib32/liblibrary.so has changed diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/tools/launcher/lib/sparc/lib64/lib64/liblibrary.so Binary file jdk/test/tools/launcher/lib/sparc/lib64/lib64/liblibrary.so has changed diff -r c4a3e3140f7b -r 88db80c8e49c jdk/test/tools/launcher/lib/sparc/lib64/liblibrary.so Binary file jdk/test/tools/launcher/lib/sparc/lib64/liblibrary.so has changed diff -r c4a3e3140f7b -r 88db80c8e49c langtools/.hgtags --- a/langtools/.hgtags Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/.hgtags Wed Jul 05 17:18:12 2017 +0200 @@ -75,3 +75,4 @@ 3b38f3aa3dc388eef0737a9fba99f54a1602ee3b jdk7-b98 005bec70ca27239bdd4e6169b9b078507401aa72 jdk7-b99 d1d7595fa824925651f09b8ffcb86c9cf39807be jdk7-b100 +20a8fe72ee7b673f59c319a5222fe0eebbd92082 jdk7-b101 diff -r c4a3e3140f7b -r 88db80c8e49c langtools/src/share/classes/com/sun/tools/javac/code/Kinds.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Kinds.java Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Kinds.java Wed Jul 05 17:18:12 2017 +0200 @@ -92,7 +92,7 @@ public static final int ABSENT_TYP = ERRONEOUS+8; // missing type public enum KindName implements Formattable { - ANNOTATION("kindname.interface"), + ANNOTATION("kindname.annotation"), CONSTRUCTOR("kindname.constructor"), INTERFACE("kindname.interface"), ENUM("kindname.enum"), diff -r c4a3e3140f7b -r 88db80c8e49c langtools/src/share/classes/com/sun/tools/javac/comp/Check.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Wed Jul 05 17:18:12 2017 +0200 @@ -563,7 +563,7 @@ while (args.nonEmpty()) { if (args.head.tag == WILDCARD) return typeTagError(pos, - Log.getLocalizedString("type.req.exact"), + diags.fragment("type.req.exact"), args.head); args = args.tail; } diff -r c4a3e3140f7b -r 88db80c8e49c langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Wed Jul 05 17:18:12 2017 +0200 @@ -674,6 +674,40 @@ return rs.resolveInternalField(pos, attrEnv, qual, name); } + /** Anon inner classes are used as access constructor tags. + * accessConstructorTag will use an existing anon class if one is available, + * and synthethise a class (with makeEmptyClass) if one is not available. + * However, there is a small possibility that an existing class will not + * be generated as expected if it is inside a conditional with a constant + * expression. If that is found to be the case, create an empty class here. + */ + private void checkAccessConstructorTags() { + for (List l = accessConstrTags; l.nonEmpty(); l = l.tail) { + ClassSymbol c = l.head; + if (isTranslatedClassAvailable(c)) + continue; + // Create class definition tree. + JCClassDecl cdef = make.ClassDef( + make.Modifiers(STATIC | SYNTHETIC), names.empty, + List.nil(), + null, List.nil(), List.nil()); + cdef.sym = c; + cdef.type = c.type; + // add it to the list of classes to be generated + translated.append(cdef); + } + } + // where + private boolean isTranslatedClassAvailable(ClassSymbol c) { + for (JCTree tree: translated) { + if (tree.getTag() == JCTree.CLASSDEF + && ((JCClassDecl) tree).sym == c) { + return true; + } + } + return false; + } + /************************************************************************** * Access methods *************************************************************************/ @@ -718,6 +752,10 @@ */ private Map accessConstrs; + /** A list of all class symbols used for access constructor tags. + */ + private List accessConstrTags; + /** A queue for all accessed symbols. */ private ListBuffer accessed; @@ -1138,6 +1176,8 @@ ClassSymbol ctag = chk.compiled.get(flatname); if (ctag == null) ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass); + // keep a record of all tags, to verify that all are generated as required + accessConstrTags = accessConstrTags.prepend(ctag); return ctag; } @@ -3394,6 +3434,7 @@ accessNums = new HashMap(); accessSyms = new HashMap(); accessConstrs = new HashMap(); + accessConstrTags = List.nil(); accessed = new ListBuffer(); translate(cdef, (JCExpression)null); for (List l = accessed.toList(); l.nonEmpty(); l = l.tail) @@ -3401,6 +3442,7 @@ for (EnumMapping map : enumSwitchMap.values()) map.translate(); checkConflicts(this.translated.toList()); + checkAccessConstructorTags(); translated = this.translated; } finally { // note that recursive invocations of this method fail hard @@ -3420,6 +3462,7 @@ accessNums = null; accessSyms = null; accessConstrs = null; + accessConstrTags = null; accessed = null; enumSwitchMap.clear(); } diff -r c4a3e3140f7b -r 88db80c8e49c langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Wed Jul 05 17:18:12 2017 +0200 @@ -111,14 +111,14 @@ try { versionRB = ResourceBundle.getBundle(versionRBName); } catch (MissingResourceException e) { - return Log.getLocalizedString("version.resource.missing", System.getProperty("java.version")); + return Log.getLocalizedString("version.not.available"); } } try { return versionRB.getString(key); } catch (MissingResourceException e) { - return Log.getLocalizedString("version.unknown", System.getProperty("java.version")); + return Log.getLocalizedString("version.not.available"); } } diff -r c4a3e3140f7b -r 88db80c8e49c langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java --- a/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java Wed Jul 05 17:18:12 2017 +0200 @@ -419,7 +419,7 @@ putChar(ch); } else { if (!allowUnderscoresInLiterals) { - lexError("unsupported.underscore", source.name); + lexError("unsupported.underscore.lit", source.name); allowUnderscoresInLiterals = true; } } diff -r c4a3e3140f7b -r 88db80c8e49c langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Jul 05 17:18:12 2017 +0200 @@ -637,6 +637,9 @@ compiler.misc.count.warn.plural=\ {0} warnings +compiler.misc.version.not.available=\ + (version info not available) + ## extra output when using -verbose (JavaCompiler) compiler.misc.verbose.checking.attribution=\ @@ -1036,7 +1039,7 @@ ## diagnostics whose key ends in ".1" compiler.misc.undetermined.type=\ undetermined type -ncompiler.misc.type.variable.has.undetermined.type=\ +compiler.misc.type.variable.has.undetermined.type=\ type variable {0} has undetermined type compiler.misc.no.unique.maximal.instance.exists=\ no unique maximal instance exists for type variable {0} with upper bounds {1} @@ -1122,6 +1125,8 @@ @interface compiler.misc.kindname.constructor=\ constructor +compiler.misc.kindname.enum=\ + enum compiler.misc.kindname.interface=\ interface compiler.misc.kindname.static=\ @@ -1256,6 +1261,10 @@ enums are not supported in -source {0}\n\ (use -source 5 or higher to enable enums) +compiler.err.diamond.not.supported.in.source=\ + diamond operator is not supported in -source {0}\n\ +(use -source 7 or higher to enable multi-catch statement) + compiler.err.multicatch.not.supported.in.source=\ multi-catch statement is not supported in -source {0}\n\ (use -source 7 or higher to enable multi-catch statement) diff -r c4a3e3140f7b -r 88db80c8e49c langtools/src/share/classes/javax/lang/model/element/ElementKind.java --- a/langtools/src/share/classes/javax/lang/model/element/ElementKind.java Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/src/share/classes/javax/lang/model/element/ElementKind.java Wed Jul 05 17:18:12 2017 +0200 @@ -88,7 +88,13 @@ * An implementation-reserved element. This is not the element * you are looking for. */ - OTHER; + OTHER, + + /** + * A resource variable. + * @since 1.7 + */ + RESOURCE_VARIABLE; /** diff -r c4a3e3140f7b -r 88db80c8e49c langtools/test/tools/javac/6917288/GraphicalInstaller.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/6917288/GraphicalInstaller.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Complex example for the "access constructor tags" issue. + * This test causes Lower to evaluate all classes defined in installNext + * before they are lowered, thus preventing the use of Lower.classdefs + * as a way of determining whether a class has been translated or not. + */ +class GraphicalInstaller { + private BackgroundInstaller backgroundInstaller; + + private void installNext() { + final Integer x = 0; + class X { + Object o = new Object() { int y = x; }; + }; + new X(); + if (false) { + new Runnable(){ + public void run() { + } + }; + } + } + + private void installSuiteCommon() { + backgroundInstaller = new BackgroundInstaller(); + } + + private static class BackgroundInstaller { + private BackgroundInstaller() { + } + } +} diff -r c4a3e3140f7b -r 88db80c8e49c langtools/test/tools/javac/6917288/GraphicalInstallerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/6917288/GraphicalInstallerTest.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* @test + * @bug 6917288 + * @summary Unnamed nested class is not generated + */ + +import java.io.*; +import java.util.*; + +public class GraphicalInstallerTest { + public static void main(String... args) throws Exception { + new GraphicalInstallerTest().run(); + } + + void run() throws Exception { + File testSrc = new File(System.getProperty("test.src")); + File classes = new File("classes"); + classes.mkdirs(); + List opts = Arrays.asList("-d", classes.getPath()); + int rc = compile(opts, new File(testSrc, "GraphicalInstaller.java")); + if (rc != 0) { + error("compilation failed: rc=" + rc); + return; + } + + check(classes, + "GraphicalInstaller$1.class", + "GraphicalInstaller$1X$1.class", + "GraphicalInstaller$1X.class", + "GraphicalInstaller$BackgroundInstaller.class", + "GraphicalInstaller.class"); + + if (errors > 0) + throw new Exception(errors + " errors occurred"); + } + + /** + * Compile files with given options. + * Display any output from compiler, and return javac return code. + */ + int compile(List opts, File... files) { + List args = new ArrayList(); + args.addAll(opts); + for (File f: files) + args.add(f.getPath()); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw); + pw.close(); + String out = sw.toString(); + if (out.length() > 0) + System.err.println(out); + return rc; + } + + /** + * Check that a directory contains the expected files. + */ + void check(File dir, String... paths) { + Set found = new TreeSet(Arrays.asList(dir.list())); + Set expect = new TreeSet(Arrays.asList(paths)); + if (found.equals(expect)) + return; + for (String f: found) { + if (!expect.contains(f)) + error("Unexpected file found: " + f); + } + for (String e: expect) { + if (!found.contains(e)) + error("Expected file not found: " + e); + } + } + + /** + * Record an error message. + */ + void error(String msg) { + System.err.println(msg); + errors++; + } + + int errors; +} diff -r c4a3e3140f7b -r 88db80c8e49c langtools/test/tools/javac/6917288/T6917288.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/6917288/T6917288.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 6917288 + * @summary Unnamed nested class is not generated + */ + +import java.io.*; +import java.util.*; + +public class T6917288 { + // refers to kind of reference to an anon inner class that may be generated + enum Kind { NONE, FALSE, TRUE, ALWAYS }; + + public static void main(String... args) throws Exception { + new T6917288().run(); + } + + void run() throws Exception { + for (Kind k: Kind.values()) { + test(k); + } + + if (errors > 0) + throw new Exception(errors + " errors occurred"); + } + + /** + * Run a test case for Kind k. + */ + void test(Kind k) throws Exception { + System.err.println("Test " + (++count) + ": " + k); + File testDir = new File("test" + count); + File srcDir = new File(testDir, "src"); + srcDir.mkdirs(); + File classesDir = new File(testDir, "classes"); + classesDir.mkdirs(); + + List opts = new ArrayList(); + opts.add("-d"); + opts.add(classesDir.getPath()); + + File f = writeFile(srcDir, k); + int rc = compile(opts, f); + if (rc != 0) { + error("compilation failed: rc=" + rc); + return; + } + + check(classesDir, "Test.class", "Test$Inner.class", "Test$1.class"); + } + + /** + * Compile files with given options. + * Display any output from compiler, and return javac return code. + */ + int compile(List opts, File... files) { + List args = new ArrayList(); + args.addAll(opts); + for (File f: files) + args.add(f.getPath()); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw); + pw.close(); + String out = sw.toString(); + if (out.length() > 0) + System.err.println(out); + return rc; + } + + /** + * Check that a directory contains the expected files. + */ + void check(File dir, String... paths) { + Set found = new TreeSet(Arrays.asList(dir.list())); + Set expect = new TreeSet(Arrays.asList(paths)); + if (found.equals(expect)) + return; + for (String f: found) { + if (!expect.contains(f)) + error("Unexpected file found: " + f); + } + for (String e: expect) { + if (!found.contains(e)) + error("Expected file not found: " + e); + } + } + + /** + * Write source file for test case k. + */ + File writeFile(File dir, Kind k) throws Exception { + StringBuilder sb = new StringBuilder(); + sb.append("public class Test {\n"); + sb.append(" private Inner inner;\n"); + + // generate different cases of an anon inner class + if (k != Kind.NONE) { + sb.append(" private void m() {\n"); + sb.append(" "); + switch (k) { + case FALSE: case TRUE: + sb.append("if (" + k.toString().toLowerCase() + ") "); + } + sb.append("new Runnable() { public void run() { } };\n"); + sb.append(" }\n"); + } + + sb.append(" private void init() {\n"); + sb.append(" inner = new Inner();\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" private static class Inner {\n"); + sb.append(" private Inner() {\n"); + sb.append(" }\n"); + sb.append(" }\n"); + sb.append("}\n"); + + File f = new File(dir, "Test.java"); + FileWriter w = new FileWriter(f); + w.write(sb.toString()); + w.close(); + return f; + } + + /** + * Record an error message. + */ + void error(String msg) { + System.err.println(msg); + errors++; + } + + int count; + int errors; +} diff -r c4a3e3140f7b -r 88db80c8e49c langtools/test/tools/javac/diags/CheckResourceKeys.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/diags/CheckResourceKeys.java Wed Jul 05 17:18:12 2017 +0200 @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6964768 6964461 6964469 6964487 6964460 6964481 + * @summary need test program to validate javac resource bundles + */ + +import java.io.*; +import java.util.*; +import javax.tools.*; +import com.sun.tools.classfile.*; + +/** + * Compare string constants in javac classes against keys in javac resource bundles. + */ +public class CheckResourceKeys { + /** + * Main program. + * Options: + * -finddeadkeys + * look for keys in resource bundles that are no longer required + * -findmissingkeys + * look for keys in resource bundles that are missing + * + * @throws Exception if invoked by jtreg and errors occur + */ + public static void main(String... args) throws Exception { + CheckResourceKeys c = new CheckResourceKeys(); + if (c.run(args)) + return; + + if (is_jtreg()) + throw new Exception(c.errors + " errors occurred"); + else + System.exit(1); + } + + static boolean is_jtreg() { + return (System.getProperty("test.src") != null); + } + + /** + * Main entry point. + */ + boolean run(String... args) throws Exception { + boolean findDeadKeys = false; + boolean findMissingKeys = false; + + if (args.length == 0) { + if (is_jtreg()) { + findDeadKeys = true; + findMissingKeys = true; + } else { + System.err.println("Usage: java CheckResourceKeys "); + System.err.println("where options include"); + System.err.println(" -finddeadkeys find keys in resource bundles which are no longer required"); + System.err.println(" -findmissingkeys find keys in resource bundles that are required but missing"); + return true; + } + } else { + for (String arg: args) { + if (arg.equalsIgnoreCase("-finddeadkeys")) + findDeadKeys = true; + else if (arg.equalsIgnoreCase("-findmissingkeys")) + findMissingKeys = true; + else + error("bad option: " + arg); + } + } + + if (errors > 0) + return false; + + Set codeStrings = getCodeStrings(); + Set resourceKeys = getResourceKeys(); + + if (findDeadKeys) + findDeadKeys(codeStrings, resourceKeys); + + if (findMissingKeys) + findMissingKeys(codeStrings, resourceKeys); + + return (errors == 0); + } + + /** + * Find keys in resource bundles which are probably no longer required. + * A key is probably required if there is a string fragment in the code + * that is part of the resource key, or if the key is well-known + * according to various pragmatic rules. + */ + void findDeadKeys(Set codeStrings, Set resourceKeys) { + String[] prefixes = { + "compiler.err.", "compiler.warn.", "compiler.note.", "compiler.misc.", + "javac." + }; + for (String rk: resourceKeys) { + // some keys are used directly, without a prefix. + if (codeStrings.contains(rk)) + continue; + + // remove standard prefix + String s = null; + for (int i = 0; i < prefixes.length && s == null; i++) { + if (rk.startsWith(prefixes[i])) { + s = rk.substring(prefixes[i].length()); + } + } + if (s == null) { + error("Resource key does not start with a standard prefix: " + rk); + continue; + } + + if (codeStrings.contains(s)) + continue; + + // keys ending in .1 are often synthesized + if (s.endsWith(".1") && codeStrings.contains(s.substring(0, s.length() - 2))) + continue; + + // verbose keys are generated by ClassReader.printVerbose + if (s.startsWith("verbose.") && codeStrings.contains(s.substring(8))) + continue; + + // mandatory warning messages are synthesized with no characteristic substring + if (isMandatoryWarningString(s)) + continue; + + // check known (valid) exceptions + if (knownRequired.contains(rk)) + continue; + + // check known suspects + if (needToInvestigate.contains(rk)) + continue; + + error("Resource key not found in code: " + rk); + } + } + + /** + * The keys for mandatory warning messages are all synthesized and do not + * have a significant recognizable substring to look for. + */ + private boolean isMandatoryWarningString(String s) { + String[] bases = { "deprecated", "unchecked", "varargs", "sunapi" }; + String[] tails = { ".filename", ".filename.additional", ".plural", ".plural.additional", ".recompile" }; + for (String b: bases) { + if (s.startsWith(b)) { + String tail = s.substring(b.length()); + for (String t: tails) { + if (tail.equals(t)) + return true; + } + } + } + return false; + } + + Set knownRequired = new TreeSet(Arrays.asList( + // See Resolve.getErrorKey + "compiler.err.cant.resolve.args", + "compiler.err.cant.resolve.args.params", + "compiler.err.cant.resolve.location.args", + "compiler.err.cant.resolve.location.args.params", + // JavaCompiler, reports #errors and #warnings + "compiler.misc.count.error", + "compiler.misc.count.error.plural", + "compiler.misc.count.warn", + "compiler.misc.count.warn.plural", + // Used for LintCategory + "compiler.warn.lintOption", + // Other + "compiler.misc.base.membership" // (sic) + )); + + + Set needToInvestigate = new TreeSet(Arrays.asList( + "compiler.err.cant.read.file", // UNUSED + "compiler.err.illegal.self.ref", // UNUSED + "compiler.err.io.exception", // UNUSED + "compiler.err.limit.pool.in.class", // UNUSED + "compiler.err.name.reserved.for.internal.use", // UNUSED + "compiler.err.no.match.entry", // UNUSED + "compiler.err.not.within.bounds.explain", // UNUSED + "compiler.err.signature.doesnt.match.intf", // UNUSED + "compiler.err.signature.doesnt.match.supertype", // UNUSED + "compiler.err.type.var.more.than.once", // UNUSED + "compiler.err.type.var.more.than.once.in.result", // UNUSED + "compiler.misc.ccf.found.later.version", // UNUSED + "compiler.misc.non.denotable.type", // UNUSED + "compiler.misc.unnamed.package", // should be required, CR 6964147 + "compiler.misc.verbose.retro", // UNUSED + "compiler.misc.verbose.retro.with", // UNUSED + "compiler.misc.verbose.retro.with.list", // UNUSED + "compiler.warn.proc.type.already.exists", // TODO in JavacFiler + "javac.err.invalid.arg", // UNUSED ?? + "javac.opt.arg.class", // UNUSED ?? + "javac.opt.arg.pathname", // UNUSED ?? + "javac.opt.moreinfo", // option commented out + "javac.opt.nogj", // UNUSED + "javac.opt.printflat", // option commented out + "javac.opt.printsearch", // option commented out + "javac.opt.prompt", // option commented out + "javac.opt.retrofit", // UNUSED + "javac.opt.s", // option commented out + "javac.opt.scramble", // option commented out + "javac.opt.scrambleall" // option commented out + )); + + /** + * For all strings in the code that look like they might be fragments of + * a resource key, verify that a key exists. + */ + void findMissingKeys(Set codeStrings, Set resourceKeys) { + for (String cs: codeStrings) { + if (cs.matches("[A-Za-z][^.]*\\..*")) { + // ignore filenames (i.e. in SourceFile attribute + if (cs.matches(".*\\.java")) + continue; + // ignore package and class names + if (cs.matches("(com|java|javax|sun)\\.[A-Za-z.]+")) + continue; + // explicit known exceptions + if (noResourceRequired.contains(cs)) + continue; + // look for matching resource + if (hasMatch(resourceKeys, cs)) + continue; + error("no match for \"" + cs + "\""); + } + } + } + // where + private Set noResourceRequired = new HashSet(Arrays.asList( + // system properties + "application.home", // in Paths.java + "env.class.path", + "line.separator", + "user.dir", + // file names + "ct.sym", + "rt.jar", + "tools.jar", + // -XD option names + "process.packages", + "ignore.symbol.file", + // prefix/embedded strings + "compiler.", + "compiler.misc.", + "count.", + "illegal.", + "javac.", + "verbose." + )); + + /** + * Look for a resource that ends in this string fragment. + */ + boolean hasMatch(Set resourceKeys, String s) { + for (String rk: resourceKeys) { + if (rk.endsWith(s)) + return true; + } + return false; + } + + /** + * Get the set of strings from (most of) the javac classfiles. + */ + Set getCodeStrings() throws IOException { + Set results = new TreeSet(); + JavaCompiler c = ToolProvider.getSystemJavaCompiler(); + JavaFileManager fm = c.getStandardFileManager(null, null, null); + String[] pkgs = { + "javax.annotation.processing", + "javax.lang.model", + "javax.tools", + "com.sun.source", + "com.sun.tools.javac" + }; + for (String pkg: pkgs) { + for (JavaFileObject fo: fm.list(StandardLocation.PLATFORM_CLASS_PATH, + pkg, EnumSet.of(JavaFileObject.Kind.CLASS), true)) { + String name = fo.getName(); + // ignore resource files, and files which are not really part of javac + if (name.contains("resources") + || name.contains("Launcher.class") + || name.contains("CreateSymbols.class")) + continue; + scan(fo, results); + } + } + return results; + } + + /** + * Get the set of strings from a class file. + * Only strings that look like they might be a resource key are returned. + */ + void scan(JavaFileObject fo, Set results) throws IOException { + InputStream in = fo.openInputStream(); + try { + ClassFile cf = ClassFile.read(in); + for (ConstantPool.CPInfo cpinfo: cf.constant_pool.entries()) { + if (cpinfo.getTag() == ConstantPool.CONSTANT_Utf8) { + String v = ((ConstantPool.CONSTANT_Utf8_info) cpinfo).value; + if (v.matches("[A-Za-z0-9-_.]+")) + results.add(v); + } + } + } catch (ConstantPoolException ignore) { + } finally { + in.close(); + } + } + + /** + * Get the set of keys from the javac resource bundles. + */ + Set getResourceKeys() { + Set results = new TreeSet(); + for (String name : new String[]{"javac", "compiler"}) { + ResourceBundle b = + ResourceBundle.getBundle("com.sun.tools.javac.resources." + name); + results.addAll(b.keySet()); + } + return results; + } + + /** + * Report an error. + */ + void error(String msg) { + System.err.println("Error: " + msg); + errors++; + } + + int errors; +} diff -r c4a3e3140f7b -r 88db80c8e49c langtools/test/tools/javac/generics/6946618/T6946618c.java --- a/langtools/test/tools/javac/generics/6946618/T6946618c.java Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/test/tools/javac/generics/6946618/T6946618c.java Wed Jul 05 17:18:12 2017 +0200 @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 6946618 + * @bug 6946618 6968497 * @summary sqe test fails: javac/generics/NewOnTypeParm in pit jdk7 b91 in all platforms. * @author mcimadamore * @compile/fail/ref=T6946618c.out -XDrawDiagnostics T6946618c.java diff -r c4a3e3140f7b -r 88db80c8e49c langtools/test/tools/javac/generics/6946618/T6946618c.out --- a/langtools/test/tools/javac/generics/6946618/T6946618c.out Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/test/tools/javac/generics/6946618/T6946618c.out Wed Jul 05 17:18:12 2017 +0200 @@ -1,4 +1,4 @@ -T6946618c.java:13:24: compiler.err.type.found.req: ? extends java.lang.String, class or interface without bounds -T6946618c.java:14:24: compiler.err.type.found.req: ? super java.lang.String, class or interface without bounds -T6946618c.java:15:24: compiler.err.type.found.req: ?, class or interface without bounds +T6946618c.java:13:24: compiler.err.type.found.req: ? extends java.lang.String, (compiler.misc.type.req.exact) +T6946618c.java:14:24: compiler.err.type.found.req: ? super java.lang.String, (compiler.misc.type.req.exact) +T6946618c.java:15:24: compiler.err.type.found.req: ?, (compiler.misc.type.req.exact) 3 errors diff -r c4a3e3140f7b -r 88db80c8e49c langtools/test/tools/javac/literals/BadUnderscoreLiterals.6.out --- a/langtools/test/tools/javac/literals/BadUnderscoreLiterals.6.out Wed Jul 05 17:17:22 2017 +0200 +++ b/langtools/test/tools/javac/literals/BadUnderscoreLiterals.6.out Wed Jul 05 17:18:12 2017 +0200 @@ -1,4 +1,4 @@ -BadUnderscoreLiterals.java:14:17: compiler.err.unsupported.underscore: 1.6 +BadUnderscoreLiterals.java:14:17: compiler.err.unsupported.underscore.lit: 1.6 BadUnderscoreLiterals.java:18:15: compiler.err.illegal.underscore BadUnderscoreLiterals.java:22:19: compiler.err.illegal.underscore BadUnderscoreLiterals.java:25:14: compiler.err.unsupported.binary.lit: 1.6