From 9544f5225c9f16f4d9eb08d32d1f6bce12e5b139 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 17 Sep 2015 18:41:05 -0700 Subject: [PATCH 001/222] 8134297: NPE in GSSNameElement nameType check Reviewed-by: xuelei --- .../classes/sun/security/jgss/wrapper/GSSNameElement.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java index d09ca8d6a16..3463fd69dfa 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java @@ -159,7 +159,9 @@ public class GSSNameElement implements GSSNameSpi { int atPos = krbName.lastIndexOf('@'); if (atPos != -1) { String atRealm = krbName.substring(atPos); - if (nameType.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL) + // getNativeNameType() can modify NT_GSS_KRB5_PRINCIPAL to null + if ((nameType == null + || nameType.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL)) && new String(nameBytes).endsWith(atRealm)) { // Created from Kerberos name with realm, no need to check } else { From 0edc09be0ce2f4c2dd3a96298e09d4735ab6e890 Mon Sep 17 00:00:00 2001 From: Vadim Pakhnushev Date: Tue, 20 Oct 2015 12:08:44 +0300 Subject: [PATCH 002/222] 8139008: Better state table management Reviewed-by: prr, srl, mschoene --- .../share/native/libfontmanager/layout/StateTableProcessor2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/StateTableProcessor2.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/StateTableProcessor2.cpp index 9aa097a6f52..ab74b239d76 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/StateTableProcessor2.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/StateTableProcessor2.cpp @@ -60,6 +60,7 @@ StateTableProcessor2::StateTableProcessor2(const LEReferenceToentryTableOffset); classTable = LEReferenceTo(stHeader, success, classTableOffset); + if (LE_FAILURE(success)) return; format = SWAPW(classTable->format); stateArray = LEReferenceToArrayOf(stHeader, success, stateArrayOffset, LE_UNBOUNDED_ARRAY); From fc6a5d3bd2bb830fda0949944c1ba734d0deed1f Mon Sep 17 00:00:00 2001 From: Anthony Scarpino Date: Mon, 21 Dec 2015 10:43:40 -0800 Subject: [PATCH 003/222] 8143945: Better GCM validation Reviewed-by: xuelei, mullan --- .../com/sun/crypto/provider/GaloisCounterMode.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index 9f8f54a1823..87fa4a383f3 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -512,11 +512,17 @@ final class GaloisCounterMode extends FeedbackCipher { byte[] sOut = new byte[s.length]; GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock); gctrForSToTag.doFinal(s, 0, s.length, sOut, 0); + + // check entire authentication tag for time-consistency + int mismatch = 0; for (int i = 0; i < tagLenBytes; i++) { - if (tag[i] != sOut[i]) { - throw new AEADBadTagException("Tag mismatch!"); - } + mismatch |= tag[i] ^ sOut[i]; } + + if (mismatch != 0) { + throw new AEADBadTagException("Tag mismatch!"); + } + return len; } From e171854b1c74dfa2ea9ab5ff9982ff8050247b58 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Wed, 23 Dec 2015 02:31:34 +0000 Subject: [PATCH 004/222] 8138593: Make DSA more fair Changed nounce K generation to FIPS 186-4 B2.1 Reviewed-by: mullan --- .../classes/sun/security/provider/DSA.java | 252 ++---------------- .../TestInitSignWithMyOwnRandom.java | 6 +- .../sun/security/provider/DSA/TestDSA2.java | 4 +- 3 files changed, 30 insertions(+), 232 deletions(-) diff --git a/jdk/src/java.base/share/classes/sun/security/provider/DSA.java b/jdk/src/java.base/share/classes/sun/security/provider/DSA.java index 6f8c27a38c0..a25949742bb 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/DSA.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/DSA.java @@ -106,6 +106,18 @@ abstract class DSA extends SignatureSpi { this.p1363Format = p1363Format; } + private static void checkKey(DSAParams params, int digestLen, String mdAlgo) + throws InvalidKeyException { + // FIPS186-3 states in sec4.2 that a hash function which provides + // a lower security strength than the (L, N) pair ordinarily should + // not be used. + int valueN = params.getQ().bitLength(); + if (valueN > digestLen) { + throw new InvalidKeyException("The security strength of " + + mdAlgo + " digest algorithm is not sufficient for this key size"); + } + } + /** * Initialize the DSA object with a DSA private key. * @@ -130,6 +142,12 @@ abstract class DSA extends SignatureSpi { throw new InvalidKeyException("DSA private key lacks parameters"); } + // check key size against hash output size for signing + // skip this check for verification to minimize impact on existing apps + if (md.getAlgorithm() != "NullDigest20") { + checkKey(params, md.getDigestLength()*8, md.getAlgorithm()); + } + this.params = params; this.presetX = priv.getX(); this.presetY = null; @@ -160,7 +178,6 @@ abstract class DSA extends SignatureSpi { if (params == null) { throw new InvalidKeyException("DSA public key lacks parameters"); } - this.params = params; this.presetY = pub.getY(); this.presetX = null; @@ -406,20 +423,13 @@ abstract class DSA extends SignatureSpi { return t5.mod(q); } - // NOTE: This following impl is defined in FIPS 186-3 AppendixB.2.2. - // Original DSS algos such as SHA1withDSA and RawDSA uses a different - // algorithm defined in FIPS 186-1 Sec3.2, and thus need to override this. + // NOTE: This following impl is defined in FIPS 186-4 AppendixB.2.1. protected BigInteger generateK(BigInteger q) { SecureRandom random = getSigningRandom(); - byte[] kValue = new byte[q.bitLength()/8]; + byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8]; - while (true) { - random.nextBytes(kValue); - BigInteger k = new BigInteger(1, kValue).mod(q); - if (k.signum() > 0 && k.compareTo(q) < 0) { - return k; - } - } + random.nextBytes(kValue); + return new BigInteger(1, kValue).mod(q.subtract(BigInteger.ONE)).add(BigInteger.ONE); } // Use the application-specified SecureRandom Object if provided. @@ -504,222 +514,10 @@ abstract class DSA extends SignatureSpi { } } - static class LegacyDSA extends DSA { - /* The random seed used to generate k */ - private int[] kSeed; - /* The random seed used to generate k (specified by application) */ - private byte[] kSeedAsByteArray; - /* - * The random seed used to generate k - * (prevent the same Kseed from being used twice in a row - */ - private int[] kSeedLast; - - public LegacyDSA(MessageDigest md) throws NoSuchAlgorithmException { - this(md, false); - } - - private LegacyDSA(MessageDigest md, boolean p1363Format) - throws NoSuchAlgorithmException { - super(md, p1363Format); - } - - @Deprecated - protected void engineSetParameter(String key, Object param) { - if (key.equals("KSEED")) { - if (param instanceof byte[]) { - kSeed = byteArray2IntArray((byte[])param); - kSeedAsByteArray = (byte[])param; - } else { - debug("unrecognized param: " + key); - throw new InvalidParameterException("kSeed not a byte array"); - } - } else { - throw new InvalidParameterException("Unsupported parameter"); - } - } - - @Deprecated - protected Object engineGetParameter(String key) { - if (key.equals("KSEED")) { - return kSeedAsByteArray; - } else { - return null; - } - } - - /* - * Please read bug report 4044247 for an alternative, faster, - * NON-FIPS approved method to generate K - */ - @Override - protected BigInteger generateK(BigInteger q) { - BigInteger k = null; - - // The application specified a kSeed for us to use. - // Note: we dis-allow usage of the same Kseed twice in a row - if (kSeed != null && !Arrays.equals(kSeed, kSeedLast)) { - k = generateKUsingKSeed(kSeed, q); - if (k.signum() > 0 && k.compareTo(q) < 0) { - kSeedLast = kSeed.clone(); - return k; - } - } - - // The application did not specify a Kseed for us to use. - // We'll generate a new Kseed by getting random bytes from - // a SecureRandom object. - SecureRandom random = getSigningRandom(); - - while (true) { - int[] seed = new int[5]; - - for (int i = 0; i < 5; i++) seed[i] = random.nextInt(); - - k = generateKUsingKSeed(seed, q); - if (k.signum() > 0 && k.compareTo(q) < 0) { - kSeedLast = seed; - return k; - } - } - } - - /** - * Compute k for the DSA signature as defined in the original DSS, - * i.e. FIPS186. - * - * @param seed the seed for generating k. This seed should be - * secure. This is what is referred to as the KSEED in the DSA - * specification. - * - * @param g the g parameter from the DSA key pair. - */ - private BigInteger generateKUsingKSeed(int[] seed, BigInteger q) { - - // check out t in the spec. - int[] t = { 0xEFCDAB89, 0x98BADCFE, 0x10325476, - 0xC3D2E1F0, 0x67452301 }; - // - int[] tmp = SHA_7(seed, t); - byte[] tmpBytes = new byte[tmp.length * 4]; - for (int i = 0; i < tmp.length; i++) { - int k = tmp[i]; - for (int j = 0; j < 4; j++) { - tmpBytes[(i * 4) + j] = (byte) (k >>> (24 - (j * 8))); - } - } - BigInteger k = new BigInteger(1, tmpBytes).mod(q); - return k; - } - - // Constants for each round - private static final int round1_kt = 0x5a827999; - private static final int round2_kt = 0x6ed9eba1; - private static final int round3_kt = 0x8f1bbcdc; - private static final int round4_kt = 0xca62c1d6; - - /** - * Computes set 1 thru 7 of SHA-1 on m1. */ - static int[] SHA_7(int[] m1, int[] h) { - - int[] W = new int[80]; - System.arraycopy(m1,0,W,0,m1.length); - int temp = 0; - - for (int t = 16; t <= 79; t++){ - temp = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]; - W[t] = ((temp << 1) | (temp >>>(32 - 1))); - } - - int a = h[0],b = h[1],c = h[2], d = h[3], e = h[4]; - for (int i = 0; i < 20; i++) { - temp = ((a<<5) | (a>>>(32-5))) + - ((b&c)|((~b)&d))+ e + W[i] + round1_kt; - e = d; - d = c; - c = ((b<<30) | (b>>>(32-30))); - b = a; - a = temp; - } - - // Round 2 - for (int i = 20; i < 40; i++) { - temp = ((a<<5) | (a>>>(32-5))) + - (b ^ c ^ d) + e + W[i] + round2_kt; - e = d; - d = c; - c = ((b<<30) | (b>>>(32-30))); - b = a; - a = temp; - } - - // Round 3 - for (int i = 40; i < 60; i++) { - temp = ((a<<5) | (a>>>(32-5))) + - ((b&c)|(b&d)|(c&d)) + e + W[i] + round3_kt; - e = d; - d = c; - c = ((b<<30) | (b>>>(32-30))); - b = a; - a = temp; - } - - // Round 4 - for (int i = 60; i < 80; i++) { - temp = ((a<<5) | (a>>>(32-5))) + - (b ^ c ^ d) + e + W[i] + round4_kt; - e = d; - d = c; - c = ((b<<30) | (b>>>(32-30))); - b = a; - a = temp; - } - int[] md = new int[5]; - md[0] = h[0] + a; - md[1] = h[1] + b; - md[2] = h[2] + c; - md[3] = h[3] + d; - md[4] = h[4] + e; - return md; - } - - /* - * Utility routine for converting a byte array into an int array - */ - private int[] byteArray2IntArray(byte[] byteArray) { - - int j = 0; - byte[] newBA; - int mod = byteArray.length % 4; - - // guarantee that the incoming byteArray is a multiple of 4 - // (pad with 0's) - switch (mod) { - case 3: newBA = new byte[byteArray.length + 1]; break; - case 2: newBA = new byte[byteArray.length + 2]; break; - case 1: newBA = new byte[byteArray.length + 3]; break; - default: newBA = new byte[byteArray.length + 0]; break; - } - System.arraycopy(byteArray, 0, newBA, 0, byteArray.length); - - // copy each set of 4 bytes in the byte array into an integer - int[] newSeed = new int[newBA.length / 4]; - for (int i = 0; i < newBA.length; i += 4) { - newSeed[j] = newBA[i + 3] & 0xFF; - newSeed[j] |= (newBA[i + 2] << 8) & 0xFF00; - newSeed[j] |= (newBA[i + 1] << 16) & 0xFF0000; - newSeed[j] |= (newBA[i + 0] << 24) & 0xFF000000; - j++; - } - - return newSeed; - } - } - /** * Standard SHA1withDSA implementation. */ - public static final class SHA1withDSA extends LegacyDSA { + public static final class SHA1withDSA extends DSA { public SHA1withDSA() throws NoSuchAlgorithmException { super(MessageDigest.getInstance("SHA-1")); } @@ -728,7 +526,7 @@ abstract class DSA extends SignatureSpi { /** * SHA1withDSA implementation that uses the IEEE P1363 format. */ - public static final class SHA1withDSAinP1363Format extends LegacyDSA { + public static final class SHA1withDSAinP1363Format extends DSA { public SHA1withDSAinP1363Format() throws NoSuchAlgorithmException { super(MessageDigest.getInstance("SHA-1"), true); } @@ -741,7 +539,7 @@ abstract class DSA extends SignatureSpi { * not, a SignatureException is thrown when sign()/verify() is called * per JCA spec. */ - static class Raw extends LegacyDSA { + static class Raw extends DSA { // Internal special-purpose MessageDigest impl for RawDSA // Only override whatever methods used // NOTE: no clone support diff --git a/jdk/test/java/security/Signature/TestInitSignWithMyOwnRandom.java b/jdk/test/java/security/Signature/TestInitSignWithMyOwnRandom.java index 2a2121e249d..0d2d7fd35a4 100644 --- a/jdk/test/java/security/Signature/TestInitSignWithMyOwnRandom.java +++ b/jdk/test/java/security/Signature/TestInitSignWithMyOwnRandom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,9 +55,9 @@ class TestRandomSource extends SecureRandom { int count = 0; - public int nextInt() { + @Override + public void nextBytes(byte[] rs) { count++; - return 0; } public boolean isUsed() { diff --git a/jdk/test/sun/security/provider/DSA/TestDSA2.java b/jdk/test/sun/security/provider/DSA/TestDSA2.java index 00691535ac1..320acce4880 100644 --- a/jdk/test/sun/security/provider/DSA/TestDSA2.java +++ b/jdk/test/sun/security/provider/DSA/TestDSA2.java @@ -60,8 +60,8 @@ public class TestDSA2 { boolean[] expectedToPass = { true, true, true, true, true, true, true, true }; test(1024, expectedToPass); - boolean[] expectedToPass2 = { true, true, true, true, - true, true, true, true }; + boolean[] expectedToPass2 = { true, false, true, true, + true, false, true, true }; test(2048, expectedToPass2); } From 29aeb056925592e0c463a46149d12df9b7884cbc Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 13 Jan 2016 11:23:25 -0800 Subject: [PATCH 005/222] 8146498: Better device table adjustments Reviewed-by: vadim, mschoene --- .../share/native/libfontmanager/layout/DeviceTables.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.cpp index df4df194fcf..7ea3032fe97 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.cpp @@ -45,9 +45,12 @@ const le_uint16 DeviceTable::fieldBits[] = { 2, 4, 8}; le_int16 DeviceTable::getAdjustment(const LEReferenceTo&base, le_uint16 ppem, LEErrorCode &success) const { + le_int16 result = 0; + if (LE_FAILURE(success)) { + return result; + } le_uint16 start = SWAPW(startSize); le_uint16 format = SWAPW(deltaFormat) - 1; - le_int16 result = 0; if (ppem >= start && ppem <= SWAPW(endSize) && format < FORMAT_COUNT) { le_uint16 sizeIndex = ppem - start; From 11920c3315e20a6948bea7bb7ccad45601271fca Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 13 Jan 2016 11:24:11 -0800 Subject: [PATCH 006/222] 8146494: Better ligature substitution Reviewed-by: vadim, mschoene --- .../layout/LigatureSubstProc.cpp | 20 +++++++++++++++++++ .../layout/LigatureSubstProc2.cpp | 20 +++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc.cpp index 5a94563fa5b..76131fd2193 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc.cpp @@ -71,6 +71,10 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp { LEErrorCode success = LE_NO_ERROR; const LigatureSubstitutionStateEntry *entry = entryTable.getAlias(index, success); + if (LE_FAILURE(success)) { + currGlyph++; + return 0; + } ByteOffset newState = SWAPW(entry->newStateOffset); le_uint16 flags = SWAPW(entry->flags); @@ -91,6 +95,10 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp if (actionOffset != 0) { LEReferenceTo ap(stHeader, success, actionOffset); + if (LE_FAILURE(success)) { + currGlyph++; + return newState; + } LigatureActionEntry action; le_int32 offset, i = 0, j = 0; le_int32 stack[nComponents]; @@ -101,6 +109,10 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp if (j++ > 0) { ap.addObject(success); + if (LE_FAILURE(success)) { + currGlyph++; + return newState; + } } action = SWAPL(*ap.getAlias()); @@ -124,9 +136,17 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp return newState; // get out! bad font } i += SWAPW(offsetTable.getObject(LE_GET_GLYPH(glyphStorage[componentGlyph]), success)); + if (LE_FAILURE(success)) { + currGlyph++; + return newState; + } if (action & (lafLast | lafStore)) { LEReferenceTo ligatureOffset(stHeader, success, i); + if (LE_FAILURE(success)) { + currGlyph++; + return newState; + } TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset.getAlias()); glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc2.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc2.cpp index 77e907322ed..1a4709e1d81 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc2.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc2.cpp @@ -95,6 +95,10 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp if (actionOffset != 0) { LEReferenceTo ap(stHeader, success, ligActionOffset); // byte offset + if (LE_FAILURE(success)) { + currGlyph+= dir; + return nextStateIndex; + } ap.addObject(ligActionIndex, success); LEReferenceToArrayOf ligatureTable(stHeader, success, ligatureOffset, LE_UNBOUNDED_ARRAY); LigatureActionEntry action; @@ -104,8 +108,8 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp LEReferenceToArrayOf componentTable(stHeader, success, componentOffset, LE_UNBOUNDED_ARRAY); if(LE_FAILURE(success)) { - currGlyph+= dir; - return nextStateIndex; // get out! bad font + currGlyph+= dir; + return nextStateIndex; // get out! bad font } do { @@ -114,6 +118,10 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp if (j++ > 0) { ap.addObject(success); } + if (LE_FAILURE(success)) { + currGlyph+= dir; + return nextStateIndex; + } action = SWAPL(*ap.getAlias()); @@ -129,9 +137,17 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp return nextStateIndex; // get out! bad font } i += SWAPW(componentTable(LE_GET_GLYPH(glyphStorage[componentGlyph]) + (SignExtend(offset, lafComponentOffsetMask)),success)); + if (LE_FAILURE(success)) { + currGlyph+= dir; + return nextStateIndex; + } if (action & (lafLast | lafStore)) { TTGlyphID ligatureGlyph = SWAPW(ligatureTable(i,success)); + if (LE_FAILURE(success)) { + currGlyph+= dir; + return nextStateIndex; + } glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); if(mm==nComponents) { LE_DEBUG_BAD_FONT("exceeded nComponents"); From 0aa59442eb94dc59551dbebca4ee4504cd0d7d37 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Wed, 20 Jan 2016 20:51:45 +0000 Subject: [PATCH 007/222] 8129952: Ensure thread consistency Reviewed-by: alanb, ahgross, skoivu --- .../classes/java/io/ObjectInputStream.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java index dbf10bd757d..60fc7947435 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -1915,6 +1915,8 @@ public class ObjectInputStream if (obj == null || handles.lookupException(passHandle) != null) { defaultReadFields(null, slotDesc); // skip field values } else if (slotDesc.hasReadObjectMethod()) { + ThreadDeath t = null; + boolean reset = false; SerialCallbackContext oldContext = curContext; if (oldContext != null) oldContext.check(); @@ -1933,10 +1935,19 @@ public class ObjectInputStream */ handles.markException(passHandle, ex); } finally { - curContext.setUsed(); - if (oldContext!= null) - oldContext.check(); - curContext = oldContext; + do { + try { + curContext.setUsed(); + if (oldContext!= null) + oldContext.check(); + curContext = oldContext; + reset = true; + } catch (ThreadDeath x) { + t = x; // defer until reset is true + } + } while (!reset); + if (t != null) + throw t; } /* From 83e0997bbda9529859c37fc302f665ad5ac047c9 Mon Sep 17 00:00:00 2001 From: Shanliang Jiang Date: Fri, 22 Jan 2016 13:27:09 +0100 Subject: [PATCH 008/222] 8144430: Improve JMX connections Reviewed-by: dfuchs, jbachorik, skoivu, ahgross --- .../classes/java/io/ObjectInputStream.java | 40 ++++++-- .../misc/JavaObjectInputStreamAccess.java | 41 ++++++++ .../misc/ObjectStreamClassValidator.java | 42 ++++++++ .../jdk/internal/misc/SharedSecrets.java | 16 +++- .../remote/rmi/RMIConnectorServer.java | 18 +++- .../remote/rmi/RMIJRMPServerImpl.java | 88 ++++++++++++++++- .../jmxremote/ConnectorBootstrap.java | 6 ++ .../rmi/server/DeserializationChecker.java | 93 ++++++++++++++++++ .../sun/rmi/server/MarshalInputStream.java | 42 +++++++- .../sun/rmi/server/UnicastServerRef.java | 95 +++++++++++++++++-- 10 files changed, 455 insertions(+), 26 deletions(-) create mode 100644 jdk/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/misc/ObjectStreamClassValidator.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/server/DeserializationChecker.java diff --git a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java index 60fc7947435..cd040d3d7e5 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -40,6 +40,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import static java.io.ObjectStreamClass.processQueue; +import jdk.internal.misc.JavaObjectInputStreamAccess; +import jdk.internal.misc.ObjectStreamClassValidator; +import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.Unsafe; import sun.reflect.misc.ReflectUtil; @@ -1509,23 +1512,28 @@ public class ObjectInputStream throws IOException { byte tc = bin.peekByte(); + ObjectStreamClass descriptor; switch (tc) { case TC_NULL: - return (ObjectStreamClass) readNull(); - + descriptor = (ObjectStreamClass) readNull(); + break; case TC_REFERENCE: - return (ObjectStreamClass) readHandle(unshared); - + descriptor = (ObjectStreamClass) readHandle(unshared); + break; case TC_PROXYCLASSDESC: - return readProxyDesc(unshared); - + descriptor = readProxyDesc(unshared); + break; case TC_CLASSDESC: - return readNonProxyDesc(unshared); - + descriptor = readNonProxyDesc(unshared); + break; default: throw new StreamCorruptedException( String.format("invalid type code: %02X", tc)); } + if (descriptor != null) { + validateDescriptor(descriptor); + } + return descriptor; } private boolean isCustomSubclass() { @@ -3658,4 +3666,20 @@ public class ObjectInputStream } } + private void validateDescriptor(ObjectStreamClass descriptor) { + ObjectStreamClassValidator validating = validator; + if (validating != null) { + validating.validateDescriptor(descriptor); + } + } + + // controlled access to ObjectStreamClassValidator + private volatile ObjectStreamClassValidator validator; + + private static void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator) { + ois.validator = validator; + } + static { + SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::setValidator); + } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java new file mode 100644 index 00000000000..c344f8adc7c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.internal.misc; + +import java.io.ObjectInputStream; + +/** + * The interface to specify methods for accessing {@code ObjectInputStream} + * @author sjiang + */ +public interface JavaObjectInputStreamAccess { + /** + * Sets a descriptor validating. + * @param ois stream to have the descriptors validated + * @param validator validator used to validate a descriptor. + */ + public void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator); +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/ObjectStreamClassValidator.java b/jdk/src/java.base/share/classes/jdk/internal/misc/ObjectStreamClassValidator.java new file mode 100644 index 00000000000..2b543a30721 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/ObjectStreamClassValidator.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.internal.misc; + +import java.io.ObjectStreamClass; + +/** + * A callback used by {@code ObjectInputStream} to do descriptor validation. + * + * @author sjiang + */ +public interface ObjectStreamClassValidator { + /** + * This method will be called by ObjectInputStream to + * check a descriptor just before creating an object described by this descriptor. + * The object will not be created if this method throws a {@code RuntimeException}. + * @param descriptor descriptor to be checked. + */ + public void validateDescriptor(ObjectStreamClass descriptor); +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java index 3246bde5be1..24dc4ce43a7 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * 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,9 +29,9 @@ import java.lang.module.ModuleDescriptor; import java.util.jar.JarFile; import java.io.Console; import java.io.FileDescriptor; +import java.io.ObjectInputStream; import java.security.ProtectionDomain; import java.security.AccessController; -import jdk.internal.misc.Unsafe; /** A repository of "shared secrets", which are a mechanism for calling implementation-private methods in another package without @@ -63,6 +63,7 @@ public class SharedSecrets { private static JavaAWTAccess javaAWTAccess; private static JavaAWTFontAccess javaAWTFontAccess; private static JavaBeansAccess javaBeansAccess; + private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; public static JavaUtilJarAccess javaUtilJarAccess() { if (javaUtilJarAccess == null) { @@ -262,4 +263,15 @@ public class SharedSecrets { public static void setJavaUtilResourceBundleAccess(JavaUtilResourceBundleAccess access) { javaUtilResourceBundleAccess = access; } + + public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() { + if (javaObjectInputStreamAccess == null) { + unsafe.ensureClassInitialized(ObjectInputStream.class); + } + return javaObjectInputStreamAccess; + } + + public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) { + javaObjectInputStreamAccess = access; + } } diff --git a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java index fe90422c193..a71bef5b403 100644 --- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java +++ b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ import java.util.Set; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; +import javax.management.remote.JMXAuthenticator; import javax.management.remote.JMXConnectionNotification; import javax.management.remote.JMXConnector; @@ -99,6 +100,21 @@ public class RMIConnectorServer extends JMXConnectorServer { public static final String RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE = "jmx.remote.rmi.server.socket.factory"; + /** + * Name of the attribute that specifies a list of class names acceptable + * as parameters to the {@link RMIServer#newClient(java.lang.Object) RMIServer.newClient()} + * remote method call. + *

+ * This list of classes should correspond to the transitive closure of the + * credentials class (or classes) used by the installed {@linkplain JMXAuthenticator} + * associated with the {@linkplain RMIServer} implementation. + *

+ * If the attribute is not set, or is null, then any class is + * deemed acceptable. + */ + public static final String CREDENTIAL_TYPES = + "jmx.remote.rmi.server.credential.types"; + /** *

Makes an RMIConnectorServer. * This is equivalent to calling {@link #RMIConnectorServer( diff --git a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java index 0e45c966c9c..838c092ca48 100644 --- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java +++ b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * 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,6 +39,13 @@ import javax.security.auth.Subject; import com.sun.jmx.remote.internal.RMIExporter; import com.sun.jmx.remote.util.EnvHelp; +import java.io.ObjectStreamClass; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import sun.reflect.misc.ReflectUtil; +import sun.rmi.server.DeserializationChecker; import sun.rmi.server.UnicastServerRef; import sun.rmi.server.UnicastServerRef2; @@ -52,6 +59,9 @@ import sun.rmi.server.UnicastServerRef2; * @since 1.5 */ public class RMIJRMPServerImpl extends RMIServerImpl { + + private final ExportedWrapper exportedWrapper; + /** *

Creates a new {@link RMIServer} object that will be exported * on the given port using the given socket factories.

@@ -89,10 +99,31 @@ public class RMIJRMPServerImpl extends RMIServerImpl { this.csf = csf; this.ssf = ssf; this.env = (env == null) ? Collections.emptyMap() : env; + + String[] credentialsTypes + = (String[]) this.env.get(RMIConnectorServer.CREDENTIAL_TYPES); + List types = null; + if (credentialsTypes != null) { + types = new ArrayList<>(); + for (String type : credentialsTypes) { + if (type == null) { + throw new IllegalArgumentException("A credential type is null."); + } + ReflectUtil.checkPackageAccess(type); + types.add(type); + } + } + exportedWrapper = types != null ? + new ExportedWrapper(this, types) : + null; } protected void export() throws IOException { - export(this); + if (exportedWrapper != null) { + export(exportedWrapper); + } else { + export(this); + } } private void export(Remote obj) throws RemoteException { @@ -142,7 +173,11 @@ public class RMIJRMPServerImpl extends RMIServerImpl { * RMIJRMPServerImpl has not been exported yet. */ public Remote toStub() throws IOException { - return RemoteObject.toStub(this); + if (exportedWrapper != null) { + return RemoteObject.toStub(exportedWrapper); + } else { + return RemoteObject.toStub(this); + } } /** @@ -189,11 +224,56 @@ public class RMIJRMPServerImpl extends RMIServerImpl { * server failed. */ protected void closeServer() throws IOException { - unexport(this, true); + if (exportedWrapper != null) { + unexport(exportedWrapper, true); + } else { + unexport(this, true); + } } private final int port; private final RMIClientSocketFactory csf; private final RMIServerSocketFactory ssf; private final Map env; + + private static class ExportedWrapper implements RMIServer, DeserializationChecker { + private final RMIServer impl; + private final List allowedTypes; + + private ExportedWrapper(RMIServer impl, List credentialsTypes) { + this.impl = impl; + allowedTypes = credentialsTypes; + } + + @Override + public String getVersion() throws RemoteException { + return impl.getVersion(); + } + + @Override + public RMIConnection newClient(Object credentials) throws IOException { + return impl.newClient(credentials); + } + + @Override + public void check(Method method, ObjectStreamClass descriptor, + int paramIndex, int callID) { + String type = descriptor.getName(); + if (!allowedTypes.contains(type)) { + throw new ClassCastException("Unsupported type: " + type); + } + } + + @Override + public void checkProxyClass(Method method, String[] ifaces, + int paramIndex, int callID) { + if (ifaces != null && ifaces.length > 0) { + for (String iface : ifaces) { + if (!allowedTypes.contains(iface)) { + throw new ClassCastException("Unsupported type: " + iface); + } + } + } + } + } } diff --git a/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java b/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java index 5ef0f7f1708..477b7786421 100644 --- a/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java +++ b/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java @@ -510,6 +510,9 @@ public final class ConnectorBootstrap { // This RMI server should not keep the VM alive Map env = new HashMap<>(); env.put(RMIExporter.EXPORTER_ATTRIBUTE, new PermanentExporter()); + env.put(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{ + String[].class.getName(), String.class.getName() + }); // The local connector server need only be available via the // loopback connection. @@ -740,6 +743,9 @@ public final class ConnectorBootstrap { PermanentExporter exporter = new PermanentExporter(); env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter); + env.put(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{ + String[].class.getName(), String.class.getName() + }); boolean useSocketFactory = bindAddress != null && !useSsl; diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/server/DeserializationChecker.java b/jdk/src/java.rmi/share/classes/sun/rmi/server/DeserializationChecker.java new file mode 100644 index 00000000000..8182b10bfbe --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/DeserializationChecker.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.rmi.server; + +import java.io.ObjectStreamClass; +import java.lang.reflect.Method; + +/** + * Implementing this interface to have a deserialization control when RMI + * dispatches a remote request. If an exported object implements this interface, + * RMI dispatching mechanism will call the method {@code check} every time + * deserialising a remote object for invoking a method of the exported object. + * + * @author sjiang + */ +public interface DeserializationChecker { + /** + * Will be called to check a descriptor. + * This method may be called 2 times, the first time is when a descriptor is read + * from the stream, the second is just before creating an object described + * by this descriptor. + * + * @param method the method invoked from a remote request. + * @param descriptor The descriptor of the class of any object deserialised + * while deserialising the parameter. The first descriptor will be that of + * the top level object (the concrete class of the parameter itself); + * Subsequent calls with the same {@code method}, {@code paramIndex} and + * {@code callID} will correspond to objects contained in the parameter. + * @param paramIndex an index indicates the position of a parameter in the + * method. This index will be reused for deserialising all + * objects contained in the parameter object. For example, the parameter + * being deserialised is a {@code List}, all deserialisation calls for its + * elements will have same index. + * @param callID a unique ID identifying one + * time method invocation, the same ID is used for deserialization call of + * all parameters within the method. + */ + public void check(Method method, + ObjectStreamClass descriptor, + int paramIndex, + int callID); + + /** + * Will be called to validate a Proxy interfaces from a remote user before loading it. + * @param method the method invoked from a remote request. + * @param ifaces a string table of all interfaces implemented by the proxy to be checked. + * @param paramIndex an index indicates the position of a parameter in the + * method. This index will be reused for deserialising all + * objects contained in the parameter object. For example, the parameter + * being deserialised is a {@code List}, all deserialisation calls for its + * elements will have same index. + * @param callID a unique ID identifying one + * time method invocation, the same ID is used for deserialization call of + * all parameters within the method. + */ + public void checkProxyClass(Method method, + String[] ifaces, + int paramIndex, + int callID); + + /** + * Inform of the completion of parameter deserialisation for a method invocation. + * This is useful if the last parameter is a complex object, like a {@code List} + * which elements are complex object too. + * + * The default implementation does nothing. + * @param callID the ID identifying a method invocation. + */ + public default void end(int callID) {} +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java index 3453e61f517..59c0be3360e 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * 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,13 +30,13 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.io.StreamCorruptedException; -import java.net.URL; import java.util.*; import java.security.AccessControlException; import java.security.Permission; - import java.rmi.server.RMIClassLoader; import java.security.PrivilegedAction; +import jdk.internal.misc.ObjectStreamClassValidator; +import jdk.internal.misc.SharedSecrets; /** * MarshalInputStream is an extension of ObjectInputStream. When resolving @@ -54,6 +54,11 @@ import java.security.PrivilegedAction; * @author Peter Jones */ public class MarshalInputStream extends ObjectInputStream { + interface StreamChecker extends ObjectStreamClassValidator { + void checkProxyInterfaceNames(String[] ifaces); + } + + private volatile StreamChecker streamChecker = null; /** * Value of "java.rmi.server.useCodebaseOnly" property, @@ -123,7 +128,7 @@ public class MarshalInputStream extends ObjectInputStream { throws IOException, StreamCorruptedException { super(in); - } + } /** * Returns a callback previously registered via the setDoneCallback @@ -240,6 +245,11 @@ public class MarshalInputStream extends ObjectInputStream { protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { + StreamChecker checker = streamChecker; + if (checker != null) { + checker.checkProxyInterfaceNames(interfaces); + } + /* * Always read annotation written by MarshalOutputStream. */ @@ -319,4 +329,28 @@ public class MarshalInputStream extends ObjectInputStream { void useCodebaseOnly() { useCodebaseOnly = true; } + + synchronized void setStreamChecker(StreamChecker checker) { + streamChecker = checker; + SharedSecrets.getJavaObjectInputStreamAccess().setValidator(this, checker); + } + @Override + protected ObjectStreamClass readClassDescriptor() throws IOException, + ClassNotFoundException { + ObjectStreamClass descriptor = super.readClassDescriptor(); + + validateDesc(descriptor); + + return descriptor; + } + + private void validateDesc(ObjectStreamClass descriptor) { + StreamChecker checker; + synchronized (this) { + checker = streamChecker; + } + if (checker != null) { + checker.validateDescriptor(descriptor); + } + } } diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java index b608f237cf5..3c57aa4b2d2 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ package sun.rmi.server; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.io.PrintStream; +import java.io.ObjectStreamClass; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.rmi.MarshalException; @@ -52,6 +52,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; +import java.util.concurrent.atomic.AtomicInteger; import sun.rmi.runtime.Log; import sun.rmi.transport.LiveRef; import sun.rmi.transport.Target; @@ -116,6 +117,8 @@ public class UnicastServerRef extends UnicastRef private static final Map,?> withoutSkeletons = Collections.synchronizedMap(new WeakHashMap,Void>()); + private final AtomicInteger methodCallIDCount = new AtomicInteger(0); + /** * Create a new (empty) Unicast server remote reference. */ @@ -297,14 +300,11 @@ public class UnicastServerRef extends UnicastRef logCall(obj, method); // unmarshal parameters - Class[] types = method.getParameterTypes(); - Object[] params = new Object[types.length]; + Object[] params = null; try { unmarshalCustomCallData(in); - for (int i = 0; i < types.length; i++) { - params[i] = unmarshalValue(types[i], in); - } + params = unmarshalParameters(obj, method, marshalStream); } catch (java.io.IOException e) { throw new UnmarshalException( "error unmarshalling arguments", e); @@ -565,4 +565,85 @@ public class UnicastServerRef extends UnicastRef return map; } } + + /** + * Unmarshal parameters for the given method of the given instance over + * the given marshalinputstream. Perform any necessary checks. + */ + private Object[] unmarshalParameters(Object obj, Method method, MarshalInputStream in) + throws IOException, ClassNotFoundException { + return (obj instanceof DeserializationChecker) ? + unmarshalParametersChecked((DeserializationChecker)obj, method, in) : + unmarshalParametersUnchecked(method, in); + } + + /** + * Unmarshal parameters for the given method of the given instance over + * the given marshalinputstream. Do not perform any additional checks. + */ + private Object[] unmarshalParametersUnchecked(Method method, ObjectInput in) + throws IOException, ClassNotFoundException { + Class[] types = method.getParameterTypes(); + Object[] params = new Object[types.length]; + for (int i = 0; i < types.length; i++) { + params[i] = unmarshalValue(types[i], in); + } + return params; + } + + /** + * Unmarshal parameters for the given method of the given instance over + * the given marshalinputstream. Do perform all additional checks. + */ + private Object[] unmarshalParametersChecked( + DeserializationChecker checker, + Method method, MarshalInputStream in) + throws IOException, ClassNotFoundException { + int callID = methodCallIDCount.getAndIncrement(); + MyChecker myChecker = new MyChecker(checker, method, callID); + in.setStreamChecker(myChecker); + try { + Class[] types = method.getParameterTypes(); + Object[] values = new Object[types.length]; + for (int i = 0; i < types.length; i++) { + myChecker.setIndex(i); + values[i] = unmarshalValue(types[i], in); + } + myChecker.end(callID); + return values; + } finally { + in.setStreamChecker(null); + } + } + + private static class MyChecker implements MarshalInputStream.StreamChecker { + private final DeserializationChecker descriptorCheck; + private final Method method; + private final int callID; + private int parameterIndex; + + MyChecker(DeserializationChecker descriptorCheck, Method method, int callID) { + this.descriptorCheck = descriptorCheck; + this.method = method; + this.callID = callID; + } + + @Override + public void validateDescriptor(ObjectStreamClass descriptor) { + descriptorCheck.check(method, descriptor, parameterIndex, callID); + } + + @Override + public void checkProxyInterfaceNames(String[] ifaces) { + descriptorCheck.checkProxyClass(method, ifaces, parameterIndex, callID); + } + + void setIndex(int parameterIndex) { + this.parameterIndex = parameterIndex; + } + + void end(int callId) { + descriptorCheck.end(callId); + } + } } From 183d5aad2e36238fdc92148cbed0125b5ae7f63a Mon Sep 17 00:00:00 2001 From: Nadeesh TV Date: Thu, 21 Apr 2016 17:51:18 +0000 Subject: [PATCH 009/222] 8154050: java.time.format.DateTimeFormatter can't parse localized zone-offset Corrected the mistake in calculating parse end position Reviewed-by: rriggs, scolebourne --- .../time/format/DateTimeFormatterBuilder.java | 18 +++----- .../TCKLocalizedOffsetIdPrinterParser.java | 44 +++++++++++++++++++ 2 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 jdk/test/java/time/tck/java/time/format/TCKLocalizedOffsetIdPrinterParser.java diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index d7baf69c5b5..c77a8c5f888 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1539,8 +1539,8 @@ public final class DateTimeFormatterBuilder { *
      *  Pattern  Count  Equivalent builder methods
      *  -------  -----  --------------------------
-     *    O       1      appendLocalizedOffsetPrefixed(TextStyle.SHORT);
-     *    OOOO    4      appendLocalizedOffsetPrefixed(TextStyle.FULL);
+     *    O       1      appendLocalizedOffset(TextStyle.SHORT);
+     *    OOOO    4      appendLocalizedOffset(TextStyle.FULL);
      *    X       1      appendOffset("+HHmm","Z")
      *    XX      2      appendOffset("+HHMM","Z")
      *    XXX     3      appendOffset("+HH:MM","Z")
@@ -3519,9 +3519,7 @@ public final class DateTimeFormatterBuilder {
                 return false;
             }
             String gmtText = "GMT";  // TODO: get localized version of 'GMT'
-            if (gmtText != null) {
-                buf.append(gmtText);
-            }
+            buf.append(gmtText);
             int totalSecs = Math.toIntExact(offsetSecs);
             if (totalSecs != 0) {
                 int absHours = Math.abs((totalSecs / 3600) % 100);  // anything larger than 99 silently dropped
@@ -3565,14 +3563,12 @@ public final class DateTimeFormatterBuilder {
         @Override
         public int parse(DateTimeParseContext context, CharSequence text, int position) {
             int pos = position;
-            int end = pos + text.length();
+            int end = text.length();
             String gmtText = "GMT";  // TODO: get localized version of 'GMT'
-            if (gmtText != null) {
-                if (!context.subSequenceEquals(text, pos, gmtText, 0, gmtText.length())) {
+            if (!context.subSequenceEquals(text, pos, gmtText, 0, gmtText.length())) {
                     return ~position;
                 }
-                pos += gmtText.length();
-            }
+            pos += gmtText.length();
             // parse normal plus/minus offset
             int negative = 0;
             if (pos == end) {
diff --git a/jdk/test/java/time/tck/java/time/format/TCKLocalizedOffsetIdPrinterParser.java b/jdk/test/java/time/tck/java/time/format/TCKLocalizedOffsetIdPrinterParser.java
new file mode 100644
index 00000000000..d0a1f189e92
--- /dev/null
+++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedOffsetIdPrinterParser.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package tck.java.time.format;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test localized behavior of formatter.
+ */
+@Test
+public class TCKLocalizedOffsetIdPrinterParser {
+    @Test
+    public void test_localized_offset_parse() {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.S O")
+                                                       .withLocale(Locale.ENGLISH);
+        String date = formatter.format(ZonedDateTime.now(ZoneOffset.UTC));
+        formatter.parse(date) ;
+     }
+}

From 40263e2a3452c165a67024165c98057a277e1ff8 Mon Sep 17 00:00:00 2001
From: Lana Steuck 
Date: Thu, 21 Apr 2016 12:57:11 -0700
Subject: [PATCH 010/222] Added tag jdk-9+115 for changeset 3414aeff4a80

---
 jdk/.hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/jdk/.hgtags b/jdk/.hgtags
index e9974a728e5..74ad9bf9055 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -357,3 +357,4 @@ b2a69d66dc65ad1d3aeb3bd362cf5bb0deba040e jdk-9+111
 1565a0efe6f0ca411a6df277df1e069431c60988 jdk-9+112
 68f8be44b6a6b33dfa841ec671c0ba6e4056b372 jdk-9+113
 bb8379287f3736f38c52b2d1418784e2592461d1 jdk-9+114
+35225b837d66582037eeadeb471c13235dfd793d jdk-9+115

From ac4936ef857e31fcdbff28798e42f33e8065df64 Mon Sep 17 00:00:00 2001
From: Amy Lu 
Date: Fri, 22 Apr 2016 13:01:41 +0800
Subject: [PATCH 011/222] 8153933: Remove intermittent key from
 TimeZone/Bug6772689.java and move back to tier1

Reviewed-by: darcy
---
 jdk/test/TEST.groups                        | 2 --
 jdk/test/java/util/TimeZone/Bug6772689.java | 1 -
 2 files changed, 3 deletions(-)

diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups
index cf3f0abfd9d..673b0862d5c 100644
--- a/jdk/test/TEST.groups
+++ b/jdk/test/TEST.groups
@@ -32,7 +32,6 @@ tier1 = \
     -java/util/WeakHashMap/GCDuringIteration.java \
     -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \
     -java/util/concurrent/forkjoin/FJExceptionTableLeak.java \
-    -java/util/TimeZone/Bug6772689.java \
     sun/nio/cs/ISO8859x.java \
     java/nio/Buffer \
     com/sun/crypto/provider/Cipher \
@@ -43,7 +42,6 @@ tier2 = \
     java/util/WeakHashMap/GCDuringIteration.java \
     java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \
     java/util/concurrent/forkjoin/FJExceptionTableLeak.java \
-    java/util/TimeZone/Bug6772689.java \
     :jdk_io \
     :jdk_nio \
     -sun/nio/cs/ISO8859x.java \
diff --git a/jdk/test/java/util/TimeZone/Bug6772689.java b/jdk/test/java/util/TimeZone/Bug6772689.java
index a1ce49682b4..f730567013d 100644
--- a/jdk/test/java/util/TimeZone/Bug6772689.java
+++ b/jdk/test/java/util/TimeZone/Bug6772689.java
@@ -24,7 +24,6 @@
 /*
  * @test
  * @bug 6772689
- * @key intermittent
  * @summary Test for standard-to-daylight transitions at midnight:
  * date stays on the given day.
  */

From d9e44503b4843911e00cd3a79c3dd04f7b5c0405 Mon Sep 17 00:00:00 2001
From: Nadeesh TV 
Date: Fri, 22 Apr 2016 05:46:54 +0000
Subject: [PATCH 012/222] 8148947: DateTimeFormatter pattern letter 'g'

Handled 'g'  in the required places

Reviewed-by: rriggs, scolebourne
---
 .../java/time/format/DateTimeFormatter.java   | 11 ++--
 .../time/format/DateTimeFormatterBuilder.java | 58 ++++++++++---------
 .../java/time/temporal/JulianFields.java      | 10 +++-
 .../format/TCKDateTimeFormatterBuilder.java   | 35 ++++++++++-
 4 files changed, 80 insertions(+), 34 deletions(-)

diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java
index 3478af25761..9810a088b48 100644
--- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java
+++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * 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,6 +284,7 @@ import java.util.Set;
  *   D       day-of-year                 number            189
  *   M/L     month-of-year               number/text       7; 07; Jul; July; J
  *   d       day-of-month                number            10
+ *   g       modified-julian-day         number            2451334
  *
  *   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
  *   Y       week-based-year             year              1996; 96
@@ -308,10 +309,10 @@ import java.util.Set;
  *
  *   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
  *   z       time-zone name              zone-name         Pacific Standard Time; PST
- *   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
- *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
- *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
- *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
+ *   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00
+ *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15
+ *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15
+ *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00
  *
  *   p       pad next                    pad modifier      1
  *
diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
index c77a8c5f888..e8ca3f1e99f 100644
--- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
+++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
@@ -90,6 +90,7 @@ import java.time.chrono.IsoChronology;
 import java.time.format.DateTimeTextProvider.LocaleStore;
 import java.time.temporal.ChronoField;
 import java.time.temporal.IsoFields;
+import java.time.temporal.JulianFields;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalField;
 import java.time.temporal.TemporalQueries;
@@ -1383,6 +1384,7 @@ public final class DateTimeFormatterBuilder {
      *   D       day-of-year                 number            189
      *   M/L     month-of-year               number/text       7; 07; Jul; July; J
      *   d       day-of-month                number            10
+     *   g       modified-julian-day         number            2451334
      *
      *   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
      *   Y       week-based-year             year              1996; 96
@@ -1408,9 +1410,9 @@ public final class DateTimeFormatterBuilder {
      *   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
      *   z       time-zone name              zone-name         Pacific Standard Time; PST
      *   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
-     *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
-     *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
-     *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
+     *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15
+     *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15
+     *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00
      *
      *   p       pad next                    pad modifier      1
      *
@@ -1437,37 +1439,37 @@ public final class DateTimeFormatterBuilder {
      *    GGGG    4      appendText(ChronoField.ERA, TextStyle.FULL)
      *    GGGGG   5      appendText(ChronoField.ERA, TextStyle.NARROW)
      *
-     *    u       1      appendValue(ChronoField.YEAR, 1, 19, SignStyle.NORMAL);
-     *    uu      2      appendValueReduced(ChronoField.YEAR, 2, 2000);
-     *    uuu     3      appendValue(ChronoField.YEAR, 3, 19, SignStyle.NORMAL);
-     *    u..u    4..n   appendValue(ChronoField.YEAR, n, 19, SignStyle.EXCEEDS_PAD);
-     *    y       1      appendValue(ChronoField.YEAR_OF_ERA, 1, 19, SignStyle.NORMAL);
-     *    yy      2      appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2000);
-     *    yyy     3      appendValue(ChronoField.YEAR_OF_ERA, 3, 19, SignStyle.NORMAL);
-     *    y..y    4..n   appendValue(ChronoField.YEAR_OF_ERA, n, 19, SignStyle.EXCEEDS_PAD);
+     *    u       1      appendValue(ChronoField.YEAR, 1, 19, SignStyle.NORMAL)
+     *    uu      2      appendValueReduced(ChronoField.YEAR, 2, 2000)
+     *    uuu     3      appendValue(ChronoField.YEAR, 3, 19, SignStyle.NORMAL)
+     *    u..u    4..n   appendValue(ChronoField.YEAR, n, 19, SignStyle.EXCEEDS_PAD)
+     *    y       1      appendValue(ChronoField.YEAR_OF_ERA, 1, 19, SignStyle.NORMAL)
+     *    yy      2      appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2000)
+     *    yyy     3      appendValue(ChronoField.YEAR_OF_ERA, 3, 19, SignStyle.NORMAL)
+     *    y..y    4..n   appendValue(ChronoField.YEAR_OF_ERA, n, 19, SignStyle.EXCEEDS_PAD)
      *    Y       1      append special localized WeekFields element for numeric week-based-year
-     *    YY      2      append special localized WeekFields element for reduced numeric week-based-year 2 digits;
-     *    YYY     3      append special localized WeekFields element for numeric week-based-year (3, 19, SignStyle.NORMAL);
-     *    Y..Y    4..n   append special localized WeekFields element for numeric week-based-year (n, 19, SignStyle.EXCEEDS_PAD);
+     *    YY      2      append special localized WeekFields element for reduced numeric week-based-year 2 digits
+     *    YYY     3      append special localized WeekFields element for numeric week-based-year (3, 19, SignStyle.NORMAL)
+     *    Y..Y    4..n   append special localized WeekFields element for numeric week-based-year (n, 19, SignStyle.EXCEEDS_PAD)
      *
-     *    Q       1      appendValue(IsoFields.QUARTER_OF_YEAR);
-     *    QQ      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2);
+     *    Q       1      appendValue(IsoFields.QUARTER_OF_YEAR)
+     *    QQ      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2)
      *    QQQ     3      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.SHORT)
      *    QQQQ    4      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.FULL)
      *    QQQQQ   5      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.NARROW)
-     *    q       1      appendValue(IsoFields.QUARTER_OF_YEAR);
-     *    qq      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2);
+     *    q       1      appendValue(IsoFields.QUARTER_OF_YEAR)
+     *    qq      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2)
      *    qqq     3      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.SHORT_STANDALONE)
      *    qqqq    4      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.FULL_STANDALONE)
      *    qqqqq   5      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.NARROW_STANDALONE)
      *
-     *    M       1      appendValue(ChronoField.MONTH_OF_YEAR);
-     *    MM      2      appendValue(ChronoField.MONTH_OF_YEAR, 2);
+     *    M       1      appendValue(ChronoField.MONTH_OF_YEAR)
+     *    MM      2      appendValue(ChronoField.MONTH_OF_YEAR, 2)
      *    MMM     3      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.SHORT)
      *    MMMM    4      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.FULL)
      *    MMMMM   5      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.NARROW)
-     *    L       1      appendValue(ChronoField.MONTH_OF_YEAR);
-     *    LL      2      appendValue(ChronoField.MONTH_OF_YEAR, 2);
+     *    L       1      appendValue(ChronoField.MONTH_OF_YEAR)
+     *    LL      2      appendValue(ChronoField.MONTH_OF_YEAR, 2)
      *    LLL     3      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE)
      *    LLLL    4      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.FULL_STANDALONE)
      *    LLLLL   5      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.NARROW_STANDALONE)
@@ -1481,6 +1483,7 @@ public final class DateTimeFormatterBuilder {
      *    DD      2      appendValue(ChronoField.DAY_OF_YEAR, 2)
      *    DDD     3      appendValue(ChronoField.DAY_OF_YEAR, 3)
      *    F       1      appendValue(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH)
+     *    g..g    1..n   appendValue(JulianFields.MODIFIED_JULIAN_DAY, n, 19, SignStyle.NORMAL)
      *    E       1      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
      *    EE      2      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
      *    EEE     3      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
@@ -1539,8 +1542,8 @@ public final class DateTimeFormatterBuilder {
      * 
      *  Pattern  Count  Equivalent builder methods
      *  -------  -----  --------------------------
-     *    O       1      appendLocalizedOffset(TextStyle.SHORT);
-     *    OOOO    4      appendLocalizedOffset(TextStyle.FULL);
+     *    O       1      appendLocalizedOffset(TextStyle.SHORT)
+     *    OOOO    4      appendLocalizedOffset(TextStyle.FULL)
      *    X       1      appendOffset("+HHmm","Z")
      *    XX      2      appendOffset("+HHMM","Z")
      *    XXX     3      appendOffset("+HH:MM","Z")
@@ -1554,7 +1557,7 @@ public final class DateTimeFormatterBuilder {
      *    Z       1      appendOffset("+HHMM","+0000")
      *    ZZ      2      appendOffset("+HHMM","+0000")
      *    ZZZ     3      appendOffset("+HHMM","+0000")
-     *    ZZZZ    4      appendLocalizedOffset(TextStyle.FULL);
+     *    ZZZZ    4      appendLocalizedOffset(TextStyle.FULL)
      *    ZZZZZ   5      appendOffset("+HH:MM:ss","Z")
      * 
*

@@ -1836,6 +1839,9 @@ public final class DateTimeFormatterBuilder { throw new IllegalArgumentException("Too many pattern letters: " + cur); } break; + case 'g': + appendValue(field, count, 19, SignStyle.NORMAL); + break; default: if (count == 1) { appendValue(field); @@ -1874,6 +1880,7 @@ public final class DateTimeFormatterBuilder { FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY); // LDML FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND); // 310 (proposed for LDML) FIELD_MAP.put('N', ChronoField.NANO_OF_DAY); // 310 (proposed for LDML) + FIELD_MAP.put('g', JulianFields.MODIFIED_JULIAN_DAY); // 310 - z - time-zone names, matches LDML and SimpleDateFormat 1 to 4 // 310 - Z - matches SimpleDateFormat and LDML // 310 - V - time-zone id, matches LDML @@ -1884,7 +1891,6 @@ public final class DateTimeFormatterBuilder { // LDML - U - cycle year name, not supported by 310 yet // LDML - l - deprecated // LDML - j - not relevant - // LDML - g - modified-julian-day // LDML - v,V - extended time-zone names } diff --git a/jdk/src/java.base/share/classes/java/time/temporal/JulianFields.java b/jdk/src/java.base/share/classes/java/time/temporal/JulianFields.java index 327037981eb..7fc501cb9dd 100644 --- a/jdk/src/java.base/share/classes/java/time/temporal/JulianFields.java +++ b/jdk/src/java.base/share/classes/java/time/temporal/JulianFields.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,7 +117,13 @@ public final class JulianFields { * *

Astronomical and Scientific Notes

* The standard astronomical definition uses a fraction to indicate the time-of-day, - * thus 3.25 would represent the time 18:00, since days start at midday. + * where each day is counted from midday to midday. For example, + * a fraction of 0 represents midday, a fraction of 0.25 + * represents 18:00, a fraction of 0.5 represents midnight and a fraction + * of 0.75 represents 06:00. + *

+ * By contrast, this implementation has no fractional part, and counts + * days from midnight to midnight. * This implementation uses an integer and days starting at midnight. * The integer value for the Julian Day Number is the astronomical Julian Day value at midday * of the date in question. diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java index 696ba8109cc..2fde35b5e2c 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -661,6 +661,8 @@ public class TCKDateTimeFormatterBuilder { {"W"}, {"W"}, + {"g"}, + {"ggggg"}, }; } @@ -761,6 +763,37 @@ public class TCKDateTimeFormatterBuilder { return LocalDate.of(y, m, d); } + //----------------------------------------------------------------------- + @DataProvider(name="modJulianFieldPattern") + Object[][] data_modJuilanFieldPattern() { + return new Object[][] { + {"g", "1"}, + {"g", "123456"}, + {"gggggg", "123456"}, + }; + } + + @Test(dataProvider="modJulianFieldPattern") + public void test_modJulianFieldPattern(String pattern, String input) throws Exception { + DateTimeFormatter.ofPattern(pattern).parse(input); + } + + @DataProvider(name="modJulianFieldValues") + Object[][] data_modJuilanFieldValues() { + return new Object[][] { + {1970, 1, 1, "40587"}, + {1858, 11, 17, "0"}, + {1858, 11, 16, "-1"}, + }; + } + + @Test(dataProvider="modJulianFieldValues") + public void test_modJulianFieldValues(int y, int m, int d, String expected) throws Exception { + DateTimeFormatter df = new DateTimeFormatterBuilder().appendPattern("g").toFormatter(); + assertEquals(LocalDate.of(y, m, d).format(df), expected); + } + + //----------------------------------------------------------------------- @Test public void test_adjacent_strict_firstFixedWidth() throws Exception { From 4cd4074db4a9d554b2e5b579292106821f7a2478 Mon Sep 17 00:00:00 2001 From: Amy Lu Date: Fri, 22 Apr 2016 17:07:54 +0800 Subject: [PATCH 013/222] 8154277: JavaDoc warnings in VirtualMachineManager.java and Pool.java Reviewed-by: alanb --- .../share/classes/com/sun/jdi/VirtualMachineManager.java | 6 +++--- .../share/classes/jdk/tools/jlink/plugin/Pool.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java index 5a6fd8b596c..58c435accf3 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java @@ -257,11 +257,11 @@ import java.io.IOException; * delegate to the {@link com.sun.jdi.connect.spi.TransportService#description() * description()} method of the underlying transport service. Both * the AttachingConnector and the ListeningConnector will have two - * Connector {@link com.sun.jdi.connect.Connector$Argument Arguments}. - * A {@link com.sun.jdi.connect.Connector$StringArgument StringArgument} + * Connector {@link com.sun.jdi.connect.Connector.Argument Arguments}. + * A {@link com.sun.jdi.connect.Connector.StringArgument StringArgument} * named {@code address} is the connector argument to specify the * address to attach too, or to listen on. A - * {@link com.sun.jdi.connect.Connector$IntegerArgument IntegerArgument} + * {@link com.sun.jdi.connect.Connector.IntegerArgument IntegerArgument} * named {@code timeout} is the connector argument to specify the * timeout when attaching, or accepting. The timeout connector may be * ignored depending on if the transport service supports an attach diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java index 3645f57c5f4..380ca41ac1a 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java @@ -226,7 +226,7 @@ public abstract class Pool { *

  • For jimage content: /{module name}/{package1}/.../{packageN}/{file * name}
  • *
  • For other files (shared lib, launchers, config, ...):/{module name}/ - * {@literal bin|conf|native}/{dir1}>/.../{dirN}/{file name}
  • + * {@literal bin|conf|native}/{dir1}/.../{dirN}/{file name} * */ public static class ModuleData { From 741bd9b060d59f544558315041879f6a60b484bc Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Fri, 22 Apr 2016 09:27:35 +0000 Subject: [PATCH 014/222] 8144566: Custom HostnameVerifier disables SNI extension Reviewed-by: mullan, wetmore --- .../sun/security/ssl/SSLSocketImpl.java | 99 +++-- .../ServerName/BestEffortOnLazyConnected.java | 337 +++++++++++++++ .../https/HttpsURLConnection/ImpactOnSNI.java | 390 ++++++++++++++++++ 3 files changed, 802 insertions(+), 24 deletions(-) create mode 100644 jdk/test/javax/net/ssl/ServerName/BestEffortOnLazyConnected.java create mode 100644 jdk/test/sun/net/www/protocol/https/HttpsURLConnection/ImpactOnSNI.java diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index 412c3ec8544..95258b2ec2b 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -209,6 +209,12 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { Collection sniMatchers = Collections.emptyList(); + // Is the serverNames set to empty with SSLParameters.setServerNames()? + private boolean noSniExtension = false; + + // Is the sniMatchers set to empty with SSLParameters.setSNIMatchers()? + private boolean noSniMatcher = false; + // Configured application protocol values String[] applicationProtocols = new String[0]; @@ -642,6 +648,11 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { } super.connect(endpoint, timeout); + + if (host == null || host.length() == 0) { + useImplicitHost(false); + } + doneConnect(); } @@ -2098,41 +2109,62 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { outputRecord.setVersion(protocolVersion); } + // + // ONLY used by ClientHandshaker for the server hostname during handshaking + // synchronized String getHost() { // Note that the host may be null or empty for localhost. if (host == null || host.length() == 0) { - if (!trustNameService) { - // If the local name service is not trustworthy, reverse host - // name resolution should not be performed for endpoint - // identification. Use the application original specified - // hostname or IP address instead. - host = getOriginalHostname(getInetAddress()); - } else { - host = getInetAddress().getHostName(); - } + useImplicitHost(true); } return host; } /* - * Get the original application specified hostname. + * Try to set and use the implicit specified hostname */ - private static String getOriginalHostname(InetAddress inetAddress) { - /* - * Get the original hostname via jdk.internal.misc.SharedSecrets. - */ - JavaNetInetAddressAccess jna = SharedSecrets.getJavaNetInetAddressAccess(); - String originalHostname = jna.getOriginalHostName(inetAddress); + private synchronized void useImplicitHost(boolean noSniUpdate) { - /* - * If no application specified hostname, use the IP address. - */ - if (originalHostname == null || originalHostname.length() == 0) { - originalHostname = inetAddress.getHostAddress(); + // Note: If the local name service is not trustworthy, reverse + // host name resolution should not be performed for endpoint + // identification. Use the application original specified + // hostname or IP address instead. + + // Get the original hostname via jdk.internal.misc.SharedSecrets + InetAddress inetAddress = getInetAddress(); + if (inetAddress == null) { // not connected + return; } - return originalHostname; + JavaNetInetAddressAccess jna = + SharedSecrets.getJavaNetInetAddressAccess(); + String originalHostname = jna.getOriginalHostName(inetAddress); + if ((originalHostname != null) && + (originalHostname.length() != 0)) { + + host = originalHostname; + if (!noSniUpdate && serverNames.isEmpty() && !noSniExtension) { + serverNames = + Utilities.addToSNIServerNameList(serverNames, host); + + if (!roleIsServer && + (handshaker != null) && !handshaker.started()) { + handshaker.setSNIServerNames(serverNames); + } + } + + return; + } + + // No explicitly specified hostname, no server name indication. + if (!trustNameService) { + // The local name service is not trustworthy, use IP address. + host = inetAddress.getHostAddress(); + } else { + // Use the underlying reverse host name resolution service. + host = getInetAddress().getHostName(); + } } // ONLY used by HttpsClient to setup the URI specified hostname @@ -2144,6 +2176,10 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { this.host = host; this.serverNames = Utilities.addToSNIServerNameList(this.serverNames, this.host); + + if (!roleIsServer && (handshaker != null) && !handshaker.started()) { + handshaker.setSNIServerNames(serverNames); + } } /** @@ -2533,8 +2569,21 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { // the super implementation does not handle the following parameters params.setEndpointIdentificationAlgorithm(identificationProtocol); params.setAlgorithmConstraints(algorithmConstraints); - params.setSNIMatchers(sniMatchers); - params.setServerNames(serverNames); + + if (sniMatchers.isEmpty() && !noSniMatcher) { + // 'null' indicates none has been set + params.setSNIMatchers(null); + } else { + params.setSNIMatchers(sniMatchers); + } + + if (serverNames.isEmpty() && !noSniExtension) { + // 'null' indicates none has been set + params.setServerNames(null); + } else { + params.setServerNames(serverNames); + } + params.setUseCipherSuitesOrder(preferLocalCipherSuites); params.setMaximumPacketSize(maximumPacketSize); params.setApplicationProtocols(applicationProtocols); @@ -2568,11 +2617,13 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { List sniNames = params.getServerNames(); if (sniNames != null) { + noSniExtension = sniNames.isEmpty(); serverNames = sniNames; } Collection matchers = params.getSNIMatchers(); if (matchers != null) { + noSniMatcher = matchers.isEmpty(); sniMatchers = matchers; } diff --git a/jdk/test/javax/net/ssl/ServerName/BestEffortOnLazyConnected.java b/jdk/test/javax/net/ssl/ServerName/BestEffortOnLazyConnected.java new file mode 100644 index 00000000000..ba3e5f10e50 --- /dev/null +++ b/jdk/test/javax/net/ssl/ServerName/BestEffortOnLazyConnected.java @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + +/** + * @test + * @bug 8144566 + * @summary Custom HostnameVerifier disables SNI extension + * @run main/othervm BestEffortOnLazyConnected + */ + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; +import java.net.*; +import javax.net.ssl.*; + +public class BestEffortOnLazyConnected { + + /* + * ============================================================= + * Set the various variables needed for the tests, then + * specify what tests to run on each side. + */ + + /* + * Should we run the client or server in a separate thread? + * Both sides can throw exceptions, but do you have a preference + * as to which side should be the main thread. + */ + private static final boolean separateServerThread = true; + + /* + * Where do we find the keystores? + */ + private static final String pathToStores = "../etc"; + private static final String keyStoreFile = "keystore"; + private static final String trustStoreFile = "truststore"; + private static final String passwd = "passphrase"; + + /* + * Is the server ready to serve? + */ + private static volatile boolean serverReady = false; + + /* + * Turn on SSL debugging? + */ + private static final boolean debug = false; + + /* + * the fully qualified domain name of localhost + */ + private static String hostname = null; + + /* + * If the client or server is doing some kind of object creation + * that the other side depends on, and that thread prematurely + * exits, you may experience a hang. The test harness will + * terminate all hung threads after its timeout has expired, + * currently 3 minutes by default, but you might try to be + * smart about it.... + */ + + /* + * Define the server side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + private void doServerSide() throws Exception { + SSLServerSocketFactory sslssf = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + try (SSLServerSocket sslServerSocket = + (SSLServerSocket) sslssf.createServerSocket(serverPort)) { + + serverPort = sslServerSocket.getLocalPort(); + + /* + * Signal Client, we're ready for his connect. + */ + serverReady = true; + + try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) { + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + sslIS.read(); + sslOS.write(85); + sslOS.flush(); + + ExtendedSSLSession session = + (ExtendedSSLSession)sslSocket.getSession(); + if (session.getRequestedServerNames().isEmpty()) { + throw new Exception("No expected Server Name Indication"); + } + } + } + } + + /* + * Define the client side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + private void doClientSide() throws Exception { + + /* + * Wait for server to get started. + */ + while (!serverReady) { + Thread.sleep(50); + } + + SSLSocketFactory sslsf = + (SSLSocketFactory) SSLSocketFactory.getDefault(); + + try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) { + + sslSocket.connect(new InetSocketAddress(hostname, serverPort), 0); + + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + } + } + + + /* + * ============================================================= + * The remainder is just support stuff + */ + + // use any free port by default + private volatile int serverPort = 0; + + private volatile Exception serverException = null; + private volatile Exception clientException = null; + + public static void main(String[] args) throws Exception { + String keyFilename = + System.getProperty("test.src", ".") + "/" + pathToStores + + "/" + keyStoreFile; + String trustFilename = + System.getProperty("test.src", ".") + "/" + pathToStores + + "/" + trustStoreFile; + + System.setProperty("javax.net.ssl.keyStore", keyFilename); + System.setProperty("javax.net.ssl.keyStorePassword", passwd); + System.setProperty("javax.net.ssl.trustStore", trustFilename); + System.setProperty("javax.net.ssl.trustStorePassword", passwd); + + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + + try { + hostname = InetAddress.getLocalHost().getCanonicalHostName(); + } catch (UnknownHostException uhe) { + System.out.println( + "Ignore the test as the local hostname cannot be determined"); + + return; + } + + System.out.println( + "The fully qualified domain name of the local host is " + + hostname); + // Ignore the test if the hostname does not sound like a domain name. + if ((hostname == null) || hostname.isEmpty() || + hostname.startsWith("localhost") || + Character.isDigit(hostname.charAt(hostname.length() - 1))) { + + System.out.println("Ignore the test as the local hostname " + + "cannot be determined as fully qualified domain name"); + + return; + } + + /* + * Start the tests. + */ + new BestEffortOnLazyConnected(); + } + + private Thread clientThread = null; + private Thread serverThread = null; + + /* + * Primary constructor, used to drive remainder of the test. + * + * Fork off the other side, then do your work. + */ + BestEffortOnLazyConnected() throws Exception { + try { + if (separateServerThread) { + startServer(true); + startClient(false); + } else { + startClient(true); + startServer(false); + } + } catch (Exception e) { + // swallow for now. Show later + } + + /* + * Wait for other side to close down. + */ + if (separateServerThread) { + serverThread.join(); + } else { + clientThread.join(); + } + + /* + * When we get here, the test is pretty much over. + * Which side threw the error? + */ + Exception local; + Exception remote; + String whichRemote; + + if (separateServerThread) { + remote = serverException; + local = clientException; + whichRemote = "server"; + } else { + remote = clientException; + local = serverException; + whichRemote = "client"; + } + + /* + * If both failed, return the curthread's exception, but also + * print the remote side Exception + */ + if ((local != null) && (remote != null)) { + System.out.println(whichRemote + " also threw:"); + remote.printStackTrace(); + System.out.println(); + throw local; + } + + if (remote != null) { + throw remote; + } + + if (local != null) { + throw local; + } + } + + private void startServer(boolean newThread) throws Exception { + if (newThread) { + serverThread = new Thread() { + public void run() { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died..."); + serverReady = true; + serverException = e; + } + } + }; + serverThread.start(); + } else { + try { + doServerSide(); + } catch (Exception e) { + serverException = e; + } finally { + serverReady = true; + } + } + } + + private void startClient(boolean newThread) throws Exception { + if (newThread) { + clientThread = new Thread() { + public void run() { + try { + doClientSide(); + } catch (Exception e) { + /* + * Our client thread just died. + */ + System.err.println("Client died..."); + clientException = e; + } + } + }; + clientThread.start(); + } else { + try { + doClientSide(); + } catch (Exception e) { + clientException = e; + } + } + } +} diff --git a/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/ImpactOnSNI.java b/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/ImpactOnSNI.java new file mode 100644 index 00000000000..4e0f0bdac59 --- /dev/null +++ b/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/ImpactOnSNI.java @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + +/* + * @test + * @bug 8144566 + * @summary Custom HostnameVerifier disables SNI extension + * @run main/othervm ImpactOnSNI + */ + +import java.io.*; +import java.net.*; +import javax.net.ssl.*; + +public class ImpactOnSNI { + + /* + * ============================================================= + * Set the various variables needed for the tests, then + * specify what tests to run on each side. + */ + + /* + * Should we run the client or server in a separate thread? + * Both sides can throw exceptions, but do you have a preference + * as to which side should be the main thread. + */ + private static final boolean separateServerThread = true; + + /* + * Where do we find the keystores? + */ + private static final String pathToStores = + "../../../../../../javax/net/ssl/etc"; + private static final String keyStoreFile = "keystore"; + private static final String trustStoreFile = "truststore"; + private static final String passwd = "passphrase"; + + /* + * Is the server ready to serve? + */ + private static volatile boolean serverReady = false; + + /* + * Is the connection ready to close? + */ + private static volatile boolean closeReady = false; + + /* + * Turn on SSL debugging? + */ + private static final boolean debug = false; + + /* + * Message posted + */ + private static final String postMsg = "HTTP post on a https server"; + + /* + * the fully qualified domain name of localhost + */ + private static String hostname = null; + + /* + * If the client or server is doing some kind of object creation + * that the other side depends on, and that thread prematurely + * exits, you may experience a hang. The test harness will + * terminate all hung threads after its timeout has expired, + * currently 3 minutes by default, but you might try to be + * smart about it.... + */ + + /* + * Define the server side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + private void doServerSide() throws Exception { + SSLServerSocketFactory sslssf = + (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); + try (SSLServerSocket sslServerSocket = + (SSLServerSocket)sslssf.createServerSocket(serverPort)) { + + serverPort = sslServerSocket.getLocalPort(); + + /* + * Signal Client, we're ready for his connect. + */ + serverReady = true; + + /* + * Accept connections + */ + try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) { + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + BufferedReader br = + new BufferedReader(new InputStreamReader(sslIS)); + PrintStream ps = new PrintStream(sslOS); + + // process HTTP POST request from client + System.out.println("status line: " + br.readLine()); + String msg = null; + while ((msg = br.readLine()) != null && msg.length() > 0); + + msg = br.readLine(); + if (msg.equals(postMsg)) { + ps.println("HTTP/1.1 200 OK\n\n"); + } else { + ps.println("HTTP/1.1 500 Not OK\n\n"); + } + ps.flush(); + + ExtendedSSLSession session = + (ExtendedSSLSession)sslSocket.getSession(); + if (session.getRequestedServerNames().isEmpty()) { + throw new Exception("No expected Server Name Indication"); + } + + // close the socket + while (!closeReady) { + Thread.sleep(50); + } + } + } + } + + /* + * Define the client side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + private void doClientSide() throws Exception { + /* + * Wait for server to get started. + */ + while (!serverReady) { + Thread.sleep(50); + } + + // Send HTTP POST request to server + URL url = new URL("https://" + hostname + ":" + serverPort); + + HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier()); + HttpsURLConnection http = (HttpsURLConnection)url.openConnection(); + http.setDoOutput(true); + + http.setRequestMethod("POST"); + PrintStream ps = new PrintStream(http.getOutputStream()); + try { + ps.println(postMsg); + ps.flush(); + if (http.getResponseCode() != 200) { + throw new RuntimeException("test Failed"); + } + } finally { + ps.close(); + http.disconnect(); + closeReady = true; + } + } + + private static class NameVerifier implements HostnameVerifier { + public boolean verify(String hostname, SSLSession session) { + return true; + } + } + + /* + * ============================================================= + * The remainder is just support stuff + */ + + // use any free port by default + private volatile int serverPort = 0; + + private volatile Exception serverException = null; + private volatile Exception clientException = null; + + public static void main(String[] args) throws Exception { + String keyFilename = + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + keyStoreFile; + String trustFilename = + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + trustStoreFile; + + System.setProperty("javax.net.ssl.keyStore", keyFilename); + System.setProperty("javax.net.ssl.keyStorePassword", passwd); + System.setProperty("javax.net.ssl.trustStore", trustFilename); + System.setProperty("javax.net.ssl.trustStorePassword", passwd); + + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + + try { + hostname = InetAddress.getLocalHost().getCanonicalHostName(); + } catch (UnknownHostException uhe) { + System.out.println( + "Ignore the test as the local hostname cannot be determined"); + + return; + } + + System.out.println( + "The fully qualified domain name of the local host is " + + hostname); + // Ignore the test if the hostname does not sound like a domain name. + if ((hostname == null) || hostname.isEmpty() || + hostname.startsWith("localhost") || + Character.isDigit(hostname.charAt(hostname.length() - 1))) { + + System.out.println("Ignore the test as the local hostname " + + "cannot be determined as fully qualified domain name"); + + return; + } + + /* + * Start the tests. + */ + new ImpactOnSNI(); + } + + private Thread clientThread = null; + private Thread serverThread = null; + + /* + * Primary constructor, used to drive remainder of the test. + * + * Fork off the other side, then do your work. + */ + ImpactOnSNI() throws Exception { + Exception startException = null; + try { + if (separateServerThread) { + startServer(true); + startClient(false); + } else { + startClient(true); + startServer(false); + } + } catch (Exception e) { + startException = e; + } + + /* + * Wait for other side to close down. + */ + if (separateServerThread) { + if (serverThread != null) { + serverThread.join(); + } + } else { + if (clientThread != null) { + clientThread.join(); + } + } + + /* + * When we get here, the test is pretty much over. + * Which side threw the error? + */ + Exception local; + Exception remote; + + if (separateServerThread) { + remote = serverException; + local = clientException; + } else { + remote = clientException; + local = serverException; + } + + Exception exception = null; + + /* + * Check various exception conditions. + */ + if ((local != null) && (remote != null)) { + // If both failed, return the curthread's exception. + local.initCause(remote); + exception = local; + } else if (local != null) { + exception = local; + } else if (remote != null) { + exception = remote; + } else if (startException != null) { + exception = startException; + } + + /* + * If there was an exception *AND* a startException, + * output it. + */ + if (exception != null) { + if (exception != startException && startException != null) { + exception.addSuppressed(startException); + } + throw exception; + } + + // Fall-through: no exception to throw! + } + + private void startServer(boolean newThread) throws Exception { + if (newThread) { + serverThread = new Thread() { + @Override + public void run() { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died..."); + serverReady = true; + serverException = e; + } + } + }; + serverThread.start(); + } else { + try { + doServerSide(); + } catch (Exception e) { + serverException = e; + } finally { + serverReady = true; + } + } + } + + private void startClient(boolean newThread) throws Exception { + if (newThread) { + clientThread = new Thread() { + @Override + public void run() { + try { + doClientSide(); + } catch (Exception e) { + /* + * Our client thread just died. + */ + System.err.println("Client died..."); + clientException = e; + } + } + }; + clientThread.start(); + } else { + try { + doClientSide(); + } catch (Exception e) { + clientException = e; + } + } + } +} From 5b392c0abcaffb23ae12d2dbc6bdfefa3a30faf6 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Fri, 22 Apr 2016 13:36:22 +0200 Subject: [PATCH 015/222] 8152667: MHs.iteratedLoop(...) throws unexpected WMTE, disallows Iterator subclasses, generates inconsistent loop result type Reviewed-by: redestad --- .../java/lang/invoke/MethodHandles.java | 21 +++-- .../java/lang/invoke/LoopCombinatorTest.java | 83 ++++++++++++++++++- 2 files changed, 94 insertions(+), 10 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 5f9fc90b54d..2b5fdfebfe9 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -4572,17 +4572,24 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); */ public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) { checkIteratedLoop(iterator, body); - final boolean voidInit = init == null || init.type().returnType() == void.class; + Class resultType = init == null ? + body == null ? void.class : body.type().returnType() : + init.type().returnType(); + boolean voidResult = resultType == void.class; + + MethodHandle initIterator; + if (iterator == null) { + MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator); + initIterator = initit.asType(initit.type().changeParameterType(0, + body.type().parameterType(voidResult ? 1 : 2))); + } else { + initIterator = iterator.asType(iterator.type().changeReturnType(Iterator.class)); + } - MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator); - MethodHandle initIterator = iterator == null ? - initit.asType(initit.type().changeParameterType(0, body.type().parameterType(voidInit ? 1 : 2))) : - iterator; - Class itype = initIterator.type().returnType(); Class ttype = body.type().parameterType(0); MethodHandle returnVar = - dropArguments(voidInit ? zero(void.class) : identity(init.type().returnType()), 0, itype); + dropArguments(voidResult ? zero(void.class) : identity(resultType), 0, Iterator.class); MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext); MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype)); diff --git a/jdk/test/java/lang/invoke/LoopCombinatorTest.java b/jdk/test/java/lang/invoke/LoopCombinatorTest.java index 1df672fb997..67edb08a8cd 100644 --- a/jdk/test/java/lang/invoke/LoopCombinatorTest.java +++ b/jdk/test/java/lang/invoke/LoopCombinatorTest.java @@ -28,6 +28,7 @@ * @bug 8150635 * @bug 8150956 * @bug 8150957 + * @bug 8152667 * @bug 8153637 * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest */ @@ -400,10 +401,15 @@ public class LoopCombinatorTest { assertTrue(caught); } - @Test - public static void testIterateVoidIterator() { + @DataProvider + static Object[][] wrongIteratorTypes() { + return new Object[][]{{void.class}, {Object.class}, {Iterable.class}}; + } + + @Test(dataProvider = "wrongIteratorTypes") + public static void testIterateVoidIterator(Class it) { boolean caught = false; - MethodType v = methodType(void.class); + MethodType v = methodType(it); try { MethodHandles.iteratedLoop(MethodHandles.empty(v), null, MethodHandles.empty(v)); } catch(IllegalArgumentException iae) { @@ -420,6 +426,77 @@ public class LoopCombinatorTest { loop.invoke(Arrays.asList("hello", "world")); } + @DataProvider + static Object[][] iterateParameters() { + MethodType i = methodType(int.class); + MethodType sil_i = methodType(int.class, String.class, int.class, List.class); + MethodType sl_v = methodType(void.class, String.class, List.class); + MethodType l_it = methodType(Iterator.class, List.class); + MethodType li_it = methodType(Iterator.class, List.class, int.class); + MethodType l_i = methodType(int.class, List.class); + MethodType _it = methodType(Iterator.class); + MethodType si_i = methodType(int.class, String.class, int.class); + MethodType s_i = methodType(int.class, String.class); + return new Object[][]{ + {null, null, sl_v}, + {null, i, sil_i}, + {null, l_i, sil_i}, + {l_it, null, sl_v}, + {l_it, i, sil_i}, + {li_it, l_i, sil_i}, + {l_it, null, sil_i}, + {li_it, null, sl_v}, + {_it, l_i, si_i}, + {_it, l_i, s_i} + }; + } + + @Test(dataProvider = "iterateParameters") + public static void testIterateParameters(MethodType it, MethodType in, MethodType bo) throws Throwable { + MethodHandle iterator = it == null ? null : MethodHandles.empty(it); + MethodHandle init = in == null ? null : MethodHandles.empty(in); + MethodHandle loop = MethodHandles.iteratedLoop(iterator, init, MethodHandles.empty(bo)); + MethodType lt = loop.type(); + if (it == null && in == null) { + assertEquals(bo.dropParameterTypes(0, 1), lt); + } else if (it == null) { + if (in.parameterCount() == 0) { + assertEquals(bo.dropParameterTypes(0, in.returnType() == void.class ? 1 : 2), lt); + } else { + assertEquals(methodType(bo.returnType(), in.parameterArray()), lt); + } + } else if (in == null) { + assertEquals(methodType(bo.returnType(), it.parameterArray()), lt); + } else if (it.parameterCount() > in.parameterCount()) { + assertEquals(methodType(bo.returnType(), it.parameterArray()), lt); + } else if (it.parameterCount() < in.parameterCount()) { + assertEquals(methodType(bo.returnType(), in.parameterArray()), lt); + } else { + // both it, in present; with equal parameter list lengths + assertEquals(it.parameterList(), lt.parameterList()); + assertEquals(in.parameterList(), lt.parameterList()); + assertEquals(bo.returnType(), lt.returnType()); + } + } + + @Test + public static void testIteratorSubclass() throws Throwable { + MethodHandle loop = MethodHandles.iteratedLoop(MethodHandles.empty(methodType(BogusIterator.class, List.class)), + null, MethodHandles.empty(methodType(void.class, String.class))); + assertEquals(methodType(void.class, List.class), loop.type()); + } + + static class BogusIterator implements Iterator { + @Override + public boolean hasNext() { + return false; + } + @Override + public Object next() { + return null; + } + } + static class Empty { static void f() { } From e53e280d376074035a3281aae0f466167ddcc06a Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Fri, 22 Apr 2016 15:05:26 +0200 Subject: [PATCH 016/222] 8154751: MethodHandles.countedLoop does not accept empty bodies Reviewed-by: redestad --- .../java/lang/invoke/MethodHandles.java | 12 ++++++++---- .../java/lang/invoke/LoopCombinatorTest.java | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 2b5fdfebfe9..9992483de04 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -4476,12 +4476,16 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) { - MethodHandle returnVar = dropArguments(init == null || init.type().returnType() == void.class ? - zero(void.class) : identity(init.type().returnType()), 0, int.class, int.class); + MethodHandle defaultResultHandle = init == null || init.type().returnType() == void.class ? + zero(void.class) : + identity(init.type().returnType()); + MethodHandle adaptedBody = body == null ? dropArguments(defaultResultHandle, 0, int.class) : body; + MethodHandle returnVar = dropArguments(defaultResultHandle, 0, int.class, int.class); MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)}; - MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar}; + MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), + returnVar}; MethodHandle[] bodyClause = {init, - filterArgument(dropArguments(body, 1, int.class), 0, + filterArgument(dropArguments(adaptedBody, 1, int.class), 0, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_decrementCounter))}; return loop(indexVar, loopLimit, bodyClause); } diff --git a/jdk/test/java/lang/invoke/LoopCombinatorTest.java b/jdk/test/java/lang/invoke/LoopCombinatorTest.java index 67edb08a8cd..5637a9958a0 100644 --- a/jdk/test/java/lang/invoke/LoopCombinatorTest.java +++ b/jdk/test/java/lang/invoke/LoopCombinatorTest.java @@ -30,6 +30,7 @@ * @bug 8150957 * @bug 8152667 * @bug 8153637 + * @bug 8154751 * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest */ @@ -347,6 +348,23 @@ public class LoopCombinatorTest { assertEquals(10, loop.invoke()); } + @Test + public static void testCountedLoopEmpty() throws Throwable { + // for (int i = 0; i < 5; ++i) { /* empty */ } + MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, null); + assertEquals(methodType(void.class), loop.type()); + loop.invoke(); + } + + @Test + public static void testCountedRangeLoopEmpty() throws Throwable { + // for (int i = -5; i < 5; ++i) { /* empty */ } + MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, -5), + MethodHandles.constant(int.class, 5), null, null); + assertEquals(methodType(void.class), loop.type()); + loop.invoke(); + } + @Test public static void testIterateSum() throws Throwable { // Integer[] a = new Integer[]{1,2,3,4,5,6}; int sum = 0; for (int e : a) { sum += e; } return sum; => 21 From cafabcafce8227c4f8146c253b51bf4962bbbbaf Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Fri, 22 Apr 2016 15:05:54 +0200 Subject: [PATCH 017/222] 8154754: MethodHandles.countedLoop errors in deriving loop arguments, result type, and local state Reviewed-by: redestad --- .../java/lang/invoke/MethodHandles.java | 24 +++-- .../java/lang/invoke/LoopCombinatorTest.java | 88 +++++++++++++++++++ 2 files changed, 104 insertions(+), 8 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 9992483de04..6c37371a57b 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -4476,16 +4476,24 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) { - MethodHandle defaultResultHandle = init == null || init.type().returnType() == void.class ? - zero(void.class) : - identity(init.type().returnType()); - MethodHandle adaptedBody = body == null ? dropArguments(defaultResultHandle, 0, int.class) : body; + Class resultType; + MethodHandle actualInit; + if (init == null) { + resultType = body == null ? void.class : body.type().returnType(); + actualInit = empty(methodType(resultType)); + } else { + resultType = init.type().returnType(); + actualInit = init; + } + MethodHandle defaultResultHandle = resultType == void.class ? zero(void.class) : identity(resultType); + MethodHandle actualBody = body == null ? dropArguments(defaultResultHandle, 0, int.class) : body; MethodHandle returnVar = dropArguments(defaultResultHandle, 0, int.class, int.class); + MethodHandle actualEnd = end == null ? constant(int.class, 0) : end; MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)}; - MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), - returnVar}; - MethodHandle[] bodyClause = {init, - filterArgument(dropArguments(adaptedBody, 1, int.class), 0, + MethodHandle[] loopLimit = {actualEnd, null, + MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar}; + MethodHandle[] bodyClause = {actualInit, + filterArgument(dropArguments(actualBody, 1, int.class), 0, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_decrementCounter))}; return loop(indexVar, loopLimit, bodyClause); } diff --git a/jdk/test/java/lang/invoke/LoopCombinatorTest.java b/jdk/test/java/lang/invoke/LoopCombinatorTest.java index 5637a9958a0..625e55c611d 100644 --- a/jdk/test/java/lang/invoke/LoopCombinatorTest.java +++ b/jdk/test/java/lang/invoke/LoopCombinatorTest.java @@ -31,6 +31,7 @@ * @bug 8152667 * @bug 8153637 * @bug 8154751 + * @bug 8154754 * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest */ @@ -326,6 +327,74 @@ public class LoopCombinatorTest { loop.invoke(); } + @Test + public static void testCountedLoopNullBody() throws Throwable { + MethodHandle h5 = MethodHandles.constant(int.class, 5); + MethodHandle h13 = MethodHandles.constant(int.class, 13); + MethodHandle loop = MethodHandles.countedLoop(h5, h13, null); + assertEquals(methodType(int.class), loop.type()); + assertEquals(13, loop.invoke()); + } + + @Test + public static void testCountedLoopNullIterations() throws Throwable { + MethodHandle loop = MethodHandles.countedLoop(null, null, null); + assertEquals(methodType(void.class), loop.type()); + loop.invoke(); + } + + @Test + public static void testCountedLoopNullInitAndBody() throws Throwable { + MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, null); + assertEquals(methodType(void.class), loop.type()); + loop.invoke(); + } + + @DataProvider + static Object[][] countedLoopBodyParameters() { + return new Object[][] { + {methodType(String.class), methodType(String.class, int.class)}, + {methodType(String.class, List.class), methodType(String.class, int.class)}, + {methodType(String.class, List.class), methodType(String.class, int.class, String.class)} + }; + } + + @Test(dataProvider = "countedLoopBodyParameters") + public static void testCountedLoopBodyParameters(MethodType initType, MethodType bodyType) throws Throwable { + MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), + MethodHandles.empty(initType), MethodHandles.empty(bodyType)); + assertEquals(initType, loop.type()); + } + + @DataProvider + static Object[][] countedLoopTypes() { + return new Object[][]{{void.class}, {int.class}, {Object.class}, {String.class}, {List.class}}; + } + + @Test(dataProvider = "countedLoopTypes") + public static void testCountedLoopBodyParametersNullInit(Class t) throws Throwable { + MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, + MethodHandles.empty(methodType(t, int.class))); + assertEquals(methodType(t), loop.type()); + loop.invoke(); + } + + @Test + public static void testCountedLoopStateDefinedByBody() throws Throwable { + MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, Counted.MH_stateBody); + assertEquals(Counted.MT_bodyDeterminesState, loop.type()); + assertEquals("sssssnull01234", loop.invoke()); + } + + @Test + public static void testCountedLoopArgsDefinedByIterations() throws Throwable { + MethodHandle loop = MethodHandles.countedLoop( + MethodHandles.dropArguments(MethodHandles.constant(int.class, 3), 0, String.class), + null, Counted.MH_append); + assertEquals(Counted.MT_iterationsDefineArgs, loop.type()); + assertEquals("hello012", loop.invoke("hello")); + } + @Test public static void testCountedRangeLoop() throws Throwable { // String s = "Lambdaman!"; for (int i = -5; i < 8; ++i) { s = "na " + s; } return s; => a well known theme @@ -839,6 +908,17 @@ public class LoopCombinatorTest { return x + counter; } + static String stateBody(int counter, String s) { + return "s" + s + counter; + } + + static String append(int counter, String localState, String loopArg) { + if (null == localState) { + return loopArg + counter; + } + return localState + counter; + } + static final Class COUNTED = Counted.class; static final MethodType MT_start = methodType(String.class, String.class); @@ -846,6 +926,8 @@ public class LoopCombinatorTest { static final MethodType MT_stepUpdateArray = methodType(void.class, int.class, int[].class); static final MethodType MT_printHello = methodType(void.class, int.class); static final MethodType MT_addCounter = methodType(int.class, int.class, int.class); + static final MethodType MT_stateBody = methodType(String.class, int.class, String.class); + static final MethodType MT_append = methodType(String.class, int.class, String.class, String.class); static final MethodHandle MH_13; static final MethodHandle MH_m5; @@ -855,11 +937,15 @@ public class LoopCombinatorTest { static final MethodHandle MH_stepUpdateArray; static final MethodHandle MH_printHello; static final MethodHandle MH_addCounter; + static final MethodHandle MH_stateBody; + static final MethodHandle MH_append; static final MethodType MT_counted = methodType(String.class, String.class); static final MethodType MT_arrayCounted = methodType(void.class, int[].class); static final MethodType MT_countedPrinting = methodType(void.class); static final MethodType MT_counterInit = methodType(int.class); + static final MethodType MT_bodyDeterminesState = methodType(String.class); + static final MethodType MT_iterationsDefineArgs = methodType(String.class, String.class); static { try { @@ -871,6 +957,8 @@ public class LoopCombinatorTest { MH_stepUpdateArray = LOOKUP.findStatic(COUNTED, "stepUpdateArray", MT_stepUpdateArray); MH_printHello = LOOKUP.findStatic(COUNTED, "printHello", MT_printHello); MH_addCounter = LOOKUP.findStatic(COUNTED, "addCounter", MT_addCounter); + MH_stateBody = LOOKUP.findStatic(COUNTED, "stateBody", MT_stateBody); + MH_append = LOOKUP.findStatic(COUNTED, "append", MT_append); } catch (Exception e) { throw new ExceptionInInitializerError(e); } From ddff1247c6f871881800a0b7456c7ba05ffd9dae Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Fri, 22 Apr 2016 09:43:19 -0700 Subject: [PATCH 018/222] 8154837: Class::getPackage with exploded modules when classes in modules defined to the boot loader Reviewed-by: alanb, chegar --- .../classes/jdk/internal/loader/BootLoader.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java index 6fc5e7d4ec8..269c193dbe4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java @@ -30,6 +30,7 @@ import java.lang.module.ModuleReference; import java.lang.reflect.Layer; import java.lang.reflect.Module; import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -184,9 +185,9 @@ public class BootLoader { /** * Define the {@code Package} with the given name. The specified - * location is a jrt URL to a named module in the run-time image, a - * file path to a module in an exploded run-time image, or the file - * path to an enty on the boot class path (java agent Boot-Class-Path + * location is a jrt URL to a named module in the run-time image, + * a file URL to a module in an exploded run-time image, or a file + * path to an entry on the boot class path (java agent Boot-Class-Path * or -Xbootclasspath/a. * *

    If the given location is a JAR file containing a manifest, @@ -194,7 +195,9 @@ public class BootLoader { * the manifest, if present. * * @param name package name - * @param location location where the package is (jrt URL or file path) + * @param location location where the package is (jrt URL or file URL + * for a named module in the run-time or exploded image; + * a file path for a package from -Xbootclasspath/a) */ static Package definePackage(String name, String location) { Module module = findModule(location); @@ -222,9 +225,9 @@ public class BootLoader { if (location.startsWith("jrt:/")) { // named module in runtime image ("jrt:/".length() == 5) mn = location.substring(5, location.length()); - } else { + } else if (location.startsWith("file:/")) { // named module in exploded image - Path path = Paths.get(location); + Path path = Paths.get(URI.create(location)); Path modulesDir = Paths.get(JAVA_HOME, "modules"); if (path.startsWith(modulesDir)) { mn = path.getFileName().toString(); From 48a86ddf3e17f7244d3e87b89d0f00b51ba0d7eb Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Fri, 22 Apr 2016 13:10:53 -0700 Subject: [PATCH 019/222] 8153330: deprecate Runtime.traceInstructions() and traceMethodCalls() Reviewed-by: alanb, dholmes, mchung --- .../share/classes/java/lang/Runtime.java | 42 +++++++------------ 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/Runtime.java b/jdk/src/java.base/share/classes/java/lang/Runtime.java index a5deffc16b8..3c73d5b61a3 100644 --- a/jdk/src/java.base/share/classes/java/lang/Runtime.java +++ b/jdk/src/java.base/share/classes/java/lang/Runtime.java @@ -718,41 +718,27 @@ public class Runtime { } /** - * Enables/Disables tracing of instructions. - * If the {@code boolean} argument is {@code true}, this - * method suggests that the Java virtual machine emit debugging - * information for each instruction in the virtual machine as it - * is executed. The format of this information, and the file or other - * output stream to which it is emitted, depends on the host environment. - * The virtual machine may ignore this request if it does not support - * this feature. The destination of the trace output is system - * dependent. - *

    - * If the {@code boolean} argument is {@code false}, this - * method causes the virtual machine to stop performing the - * detailed instruction trace it is performing. + * Not implemented, does nothing. * - * @param on {@code true} to enable instruction tracing; - * {@code false} to disable this feature. + * @deprecated + * This method was intended to control instruction tracing. + * It has been superseded by JVM-specific tracing mechanisms. + * + * @param on ignored */ + @Deprecated(since="9", forRemoval=true) public void traceInstructions(boolean on) { } /** - * Enables/Disables tracing of method calls. - * If the {@code boolean} argument is {@code true}, this - * method suggests that the Java virtual machine emit debugging - * information for each method in the virtual machine as it is - * called. The format of this information, and the file or other output - * stream to which it is emitted, depends on the host environment. The - * virtual machine may ignore this request if it does not support - * this feature. - *

    - * Calling this method with argument false suggests that the - * virtual machine cease emitting per-call debugging information. + * Not implemented, does nothing. * - * @param on {@code true} to enable instruction tracing; - * {@code false} to disable this feature. + * @deprecated + * This method was intended to control method call tracing. + * It has been superseded by JVM-specific tracing mechanisms. + * + * @param on ignored */ + @Deprecated(since="9", forRemoval=true) public void traceMethodCalls(boolean on) { } /** From 6c1f9eea71e8790bc5076204f33495cd559a5354 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Sun, 24 Apr 2016 08:44:36 +0100 Subject: [PATCH 020/222] 8154919: Remove superfluous jdk.unsupported from tools/launcher/modules/limitmods/LimitModsTest.java Reviewed-by: alanb --- jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java b/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java index f11aa003e00..0cafaf42e66 100644 --- a/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java +++ b/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java @@ -103,10 +103,9 @@ public class LimitModsTest { public void testWithAddMods() throws Exception { int exitValue; - // java -limitmods java.base -addmods java.logging,jdk.unsupported -listmods + // java -limitmods java.base -addmods java.logging -listmods exitValue = executeTestJava("-limitmods", "java.base", - "-addmods", - "java.logging,jdk.unsupported", // TODO: add bug No. + "-addmods", "java.logging", "-listmods") .outputTo(System.out) .errorTo(System.out) From 3f14fca9652114ba863e408e59e477a0b93dbc44 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Sun, 24 Apr 2016 08:51:04 +0100 Subject: [PATCH 021/222] 8147543: Remove sun.misc.ManagedLocalsThread Reviewed-by: rriggs --- .../classes/sun/misc/ManagedLocalsThread.java | 92 ------------------- 1 file changed, 92 deletions(-) delete mode 100644 jdk/src/jdk.unsupported/share/classes/sun/misc/ManagedLocalsThread.java diff --git a/jdk/src/jdk.unsupported/share/classes/sun/misc/ManagedLocalsThread.java b/jdk/src/jdk.unsupported/share/classes/sun/misc/ManagedLocalsThread.java deleted file mode 100644 index 58d9013c261..00000000000 --- a/jdk/src/jdk.unsupported/share/classes/sun/misc/ManagedLocalsThread.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 sun.misc; - -/** - * A thread that has it's thread locals, and inheritable thread - * locals erased on construction. - */ -public class ManagedLocalsThread extends Thread { - private static final jdk.internal.misc.Unsafe UNSAFE; - private static final long THREAD_LOCALS; - private static final long INHERITABLE_THREAD_LOCALS; - - public ManagedLocalsThread() { - eraseThreadLocals(); - } - - public ManagedLocalsThread(Runnable target) { - super(target); - eraseThreadLocals(); - } - - public ManagedLocalsThread(String name) { - super(name); - eraseThreadLocals(); - } - - public ManagedLocalsThread(ThreadGroup group, Runnable target) { - super(group, target); - eraseThreadLocals(); - } - - public ManagedLocalsThread(Runnable target, String name) { - super(target, name); - eraseThreadLocals(); - } - - public ManagedLocalsThread(ThreadGroup group, String name) { - super(group, name); - eraseThreadLocals(); - } - - public ManagedLocalsThread(ThreadGroup group, Runnable target, String name) { - super(group, target, name); - eraseThreadLocals(); - } - - /** - * Drops all thread locals (and inherited thread locals). - */ - public final void eraseThreadLocals() { - UNSAFE.putObject(this, THREAD_LOCALS, null); - UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null); - } - - static { - UNSAFE = jdk.internal.misc.Unsafe.getUnsafe(); - Class t = Thread.class; - try { - THREAD_LOCALS = UNSAFE.objectFieldOffset - (t.getDeclaredField("threadLocals")); - INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset - (t.getDeclaredField("inheritableThreadLocals")); - } catch (Exception e) { - throw new Error(e); - } - } -} - From 52e49f6e86dd564c1cfc1c845a0478d4996458e5 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 3 Mar 2016 12:47:46 +0100 Subject: [PATCH 022/222] 8150460: (linux|bsd|aix)_close.c: file descriptor table may become large or may not work at all Reviewed-by: dsamersoff, rriggs --- .../java.base/aix/native/libnet/aix_close.c | 133 ++++++++++++++---- .../linux/native/libnet/linux_close.c | 124 ++++++++++++++-- .../macosx/native/libnet/bsd_close.c | 133 ++++++++++++++---- 3 files changed, 317 insertions(+), 73 deletions(-) diff --git a/jdk/src/java.base/aix/native/libnet/aix_close.c b/jdk/src/java.base/aix/native/libnet/aix_close.c index 0165c9a1959..77b5daecf60 100644 --- a/jdk/src/java.base/aix/native/libnet/aix_close.c +++ b/jdk/src/java.base/aix/native/libnet/aix_close.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, SAP SE and/or its affiliates. All rights reserved. * 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,6 +51,8 @@ ... */ +#include +#include #include #include #include @@ -86,10 +89,35 @@ typedef struct { static int sigWakeup = (SIGRTMAX - 1); /* - * The fd table and the number of file descriptors + * fdTable holds one entry per file descriptor, up to a certain + * maximum. + * Theoretically, the number of possible file descriptors can get + * large, though usually it does not. Entries for small value file + * descriptors are kept in a simple table, which covers most scenarios. + * Entries for large value file descriptors are kept in an overflow + * table, which is organized as a sparse two dimensional array whose + * slabs are allocated on demand. This covers all corner cases while + * keeping memory consumption reasonable. */ -static fdEntry_t *fdTable = NULL; -static int fdCount = 0; + +/* Base table for low value file descriptors */ +static fdEntry_t* fdTable = NULL; +/* Maximum size of base table (in number of entries). */ +static const int fdTableMaxSize = 0x1000; /* 4K */ +/* Actual size of base table (in number of entries) */ +static int fdTableLen = 0; +/* Max. theoretical number of file descriptors on system. */ +static int fdLimit = 0; + +/* Overflow table, should base table not be large enough. Organized as + * an array of n slabs, each holding 64k entries. + */ +static fdEntry_t** fdOverflowTable = NULL; +/* Number of slabs in the overflow table */ +static int fdOverflowTableLen = 0; +/* Number of entries in one slab */ +static const int fdOverflowTableSlabSize = 0x10000; /* 64k */ +pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER; /* * Null signal handler @@ -108,42 +136,42 @@ void aix_close_init() { struct rlimit nbr_files; sigset_t sigset; struct sigaction sa; + int i = 0; - /* Check already initialized */ - if (fdCount > 0 && fdTable != NULL) { - return; - } - - /* - * Allocate table based on the maximum number of - * file descriptors. - */ + /* Determine the maximum number of possible file descriptors. */ if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { fprintf(stderr, "library initialization failed - " "unable to get max # of allocated fds\n"); abort(); } - fdCount = nbr_files.rlim_max; - /* - * We have a conceptual problem here, when the number of files is - * unlimited. As a kind of workaround, we ensure the table is big - * enough for handle even a large number of files. Since SAP itself - * recommends a limit of 32000 files, we just use 64000 as 'infinity'. - */ - if (nbr_files.rlim_max == RLIM_INFINITY) { - fdCount = 64000; + if (nbr_files.rlim_max != RLIM_INFINITY) { + fdLimit = nbr_files.rlim_max; + } else { + /* We just do not know. */ + fdLimit = INT_MAX; } - fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + + /* Allocate table for low value file descriptors. */ + fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize; + fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t)); if (fdTable == NULL) { fprintf(stderr, "library initialization failed - " "unable to allocate file descriptor table - out of memory"); abort(); + } else { + for (i = 0; i < fdTableLen; i ++) { + pthread_mutex_init(&fdTable[i].lock, NULL); + } } - { - int i; - for (i=0; i < fdCount; i++) { - pthread_mutex_init(&fdTable[i].lock, NULL); + /* Allocate overflow table, if needed */ + if (fdLimit > fdTableMaxSize) { + fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1; + fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*)); + if (fdOverflowTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor overflow table - out of memory"); + abort(); } } @@ -161,17 +189,60 @@ void aix_close_init() { } /* - * Return the fd table for this fd or NULL is fd out - * of range. + * Return the fd table for this fd. */ static inline fdEntry_t *getFdEntry(int fd) { - if (fd < 0 || fd >= fdCount) { + fdEntry_t* result = NULL; + + if (fd < 0) { return NULL; } - return &fdTable[fd]; + + /* This should not happen. If it does, our assumption about + * max. fd value was wrong. */ + assert(fd < fdLimit); + + if (fd < fdTableMaxSize) { + /* fd is in base table. */ + assert(fd < fdTableLen); + result = &fdTable[fd]; + } else { + /* fd is in overflow table. */ + const int indexInOverflowTable = fd - fdTableMaxSize; + const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize; + const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize; + fdEntry_t* slab = NULL; + assert(rootindex < fdOverflowTableLen); + assert(slabindex < fdOverflowTableSlabSize); + pthread_mutex_lock(&fdOverflowTableLock); + /* Allocate new slab in overflow table if needed */ + if (fdOverflowTable[rootindex] == NULL) { + fdEntry_t* const newSlab = + (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t)); + if (newSlab == NULL) { + fprintf(stderr, "Unable to allocate file descriptor overflow" + " table slab - out of memory"); + pthread_mutex_unlock(&fdOverflowTableLock); + abort(); + } else { + int i; + for (i = 0; i < fdOverflowTableSlabSize; i ++) { + pthread_mutex_init(&newSlab[i].lock, NULL); + } + fdOverflowTable[rootindex] = newSlab; + } + } + pthread_mutex_unlock(&fdOverflowTableLock); + slab = fdOverflowTable[rootindex]; + result = &slab[slabindex]; + } + + return result; + } + /* * Start a blocking operation :- * Insert thread onto thread list for the fd. diff --git a/jdk/src/java.base/linux/native/libnet/linux_close.c b/jdk/src/java.base/linux/native/libnet/linux_close.c index f2e186f731e..45ab7b4dc1b 100644 --- a/jdk/src/java.base/linux/native/libnet/linux_close.c +++ b/jdk/src/java.base/linux/native/libnet/linux_close.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ * questions. */ +#include +#include #include #include #include @@ -59,10 +61,35 @@ typedef struct { static int sigWakeup = (__SIGRTMAX - 2); /* - * The fd table and the number of file descriptors + * fdTable holds one entry per file descriptor, up to a certain + * maximum. + * Theoretically, the number of possible file descriptors can get + * large, though usually it does not. Entries for small value file + * descriptors are kept in a simple table, which covers most scenarios. + * Entries for large value file descriptors are kept in an overflow + * table, which is organized as a sparse two dimensional array whose + * slabs are allocated on demand. This covers all corner cases while + * keeping memory consumption reasonable. */ -static fdEntry_t *fdTable; -static int fdCount; + +/* Base table for low value file descriptors */ +static fdEntry_t* fdTable = NULL; +/* Maximum size of base table (in number of entries). */ +static const int fdTableMaxSize = 0x1000; /* 4K */ +/* Actual size of base table (in number of entries) */ +static int fdTableLen = 0; +/* Max. theoretical number of file descriptors on system. */ +static int fdLimit = 0; + +/* Overflow table, should base table not be large enough. Organized as + * an array of n slabs, each holding 64k entries. + */ +static fdEntry_t** fdOverflowTable = NULL; +/* Number of slabs in the overflow table */ +static int fdOverflowTableLen = 0; +/* Number of entries in one slab */ +static const int fdOverflowTableSlabSize = 0x10000; /* 64k */ +pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER; /* * Null signal handler @@ -78,18 +105,43 @@ static void __attribute((constructor)) init() { struct rlimit nbr_files; sigset_t sigset; struct sigaction sa; + int i = 0; - /* - * Allocate table based on the maximum number of - * file descriptors. - */ - getrlimit(RLIMIT_NOFILE, &nbr_files); - fdCount = nbr_files.rlim_max; - fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + /* Determine the maximum number of possible file descriptors. */ + if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { + fprintf(stderr, "library initialization failed - " + "unable to get max # of allocated fds\n"); + abort(); + } + if (nbr_files.rlim_max != RLIM_INFINITY) { + fdLimit = nbr_files.rlim_max; + } else { + /* We just do not know. */ + fdLimit = INT_MAX; + } + + /* Allocate table for low value file descriptors. */ + fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize; + fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t)); if (fdTable == NULL) { fprintf(stderr, "library initialization failed - " "unable to allocate file descriptor table - out of memory"); abort(); + } else { + for (i = 0; i < fdTableLen; i ++) { + pthread_mutex_init(&fdTable[i].lock, NULL); + } + } + + /* Allocate overflow table, if needed */ + if (fdLimit > fdTableMaxSize) { + fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1; + fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*)); + if (fdOverflowTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor overflow table - out of memory"); + abort(); + } } /* @@ -106,15 +158,57 @@ static void __attribute((constructor)) init() { } /* - * Return the fd table for this fd or NULL is fd out - * of range. + * Return the fd table for this fd. */ static inline fdEntry_t *getFdEntry(int fd) { - if (fd < 0 || fd >= fdCount) { + fdEntry_t* result = NULL; + + if (fd < 0) { return NULL; } - return &fdTable[fd]; + + /* This should not happen. If it does, our assumption about + * max. fd value was wrong. */ + assert(fd < fdLimit); + + if (fd < fdTableMaxSize) { + /* fd is in base table. */ + assert(fd < fdTableLen); + result = &fdTable[fd]; + } else { + /* fd is in overflow table. */ + const int indexInOverflowTable = fd - fdTableMaxSize; + const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize; + const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize; + fdEntry_t* slab = NULL; + assert(rootindex < fdOverflowTableLen); + assert(slabindex < fdOverflowTableSlabSize); + pthread_mutex_lock(&fdOverflowTableLock); + /* Allocate new slab in overflow table if needed */ + if (fdOverflowTable[rootindex] == NULL) { + fdEntry_t* const newSlab = + (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t)); + if (newSlab == NULL) { + fprintf(stderr, "Unable to allocate file descriptor overflow" + " table slab - out of memory"); + pthread_mutex_unlock(&fdOverflowTableLock); + abort(); + } else { + int i; + for (i = 0; i < fdOverflowTableSlabSize; i ++) { + pthread_mutex_init(&newSlab[i].lock, NULL); + } + fdOverflowTable[rootindex] = newSlab; + } + } + pthread_mutex_unlock(&fdOverflowTableLock); + slab = fdOverflowTable[rootindex]; + result = &slab[slabindex]; + } + + return result; + } /* diff --git a/jdk/src/java.base/macosx/native/libnet/bsd_close.c b/jdk/src/java.base/macosx/native/libnet/bsd_close.c index 21478ce6e5f..728ea8bf1d7 100644 --- a/jdk/src/java.base/macosx/native/libnet/bsd_close.c +++ b/jdk/src/java.base/macosx/native/libnet/bsd_close.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ * questions. */ +#include +#include #include #include #include @@ -61,18 +63,35 @@ typedef struct { static int sigWakeup = SIGIO; /* - * The fd table and the number of file descriptors + * fdTable holds one entry per file descriptor, up to a certain + * maximum. + * Theoretically, the number of possible file descriptors can get + * large, though usually it does not. Entries for small value file + * descriptors are kept in a simple table, which covers most scenarios. + * Entries for large value file descriptors are kept in an overflow + * table, which is organized as a sparse two dimensional array whose + * slabs are allocated on demand. This covers all corner cases while + * keeping memory consumption reasonable. */ -static fdEntry_t *fdTable; -static int fdCount; -/* - * This limit applies if getlimit() returns unlimited. - * Unfortunately, this means if someone wants a higher limit - * then they have to set an explicit limit, higher than this, - * which is probably counter-intuitive. +/* Base table for low value file descriptors */ +static fdEntry_t* fdTable = NULL; +/* Maximum size of base table (in number of entries). */ +static const int fdTableMaxSize = 0x1000; /* 4K */ +/* Actual size of base table (in number of entries) */ +static int fdTableLen = 0; +/* Max. theoretical number of file descriptors on system. */ +static int fdLimit = 0; + +/* Overflow table, should base table not be large enough. Organized as + * an array of n slabs, each holding 64k entries. */ -#define MAX_FD_COUNT 4096 +static fdEntry_t** fdOverflowTable = NULL; +/* Number of slabs in the overflow table */ +static int fdOverflowTableLen = 0; +/* Number of entries in one slab */ +static const int fdOverflowTableSlabSize = 0x10000; /* 64k */ +pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER; /* * Null signal handler @@ -88,26 +107,43 @@ static void __attribute((constructor)) init() { struct rlimit nbr_files; sigset_t sigset; struct sigaction sa; - int i; + int i = 0; - /* - * Allocate table based on the maximum number of - * file descriptors. - */ - getrlimit(RLIMIT_NOFILE, &nbr_files); - if (nbr_files.rlim_max == RLIM_INFINITY) { - fdCount = MAX_FD_COUNT; - } else { - fdCount = nbr_files.rlim_max; + /* Determine the maximum number of possible file descriptors. */ + if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { + fprintf(stderr, "library initialization failed - " + "unable to get max # of allocated fds\n"); + abort(); } - fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + if (nbr_files.rlim_max != RLIM_INFINITY) { + fdLimit = nbr_files.rlim_max; + } else { + /* We just do not know. */ + fdLimit = INT_MAX; + } + + /* Allocate table for low value file descriptors. */ + fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize; + fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t)); if (fdTable == NULL) { fprintf(stderr, "library initialization failed - " "unable to allocate file descriptor table - out of memory"); abort(); + } else { + for (i = 0; i < fdTableLen; i ++) { + pthread_mutex_init(&fdTable[i].lock, NULL); + } } - for (i=0; i fdTableMaxSize) { + fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1; + fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*)); + if (fdOverflowTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor overflow table - out of memory"); + abort(); + } } /* @@ -124,17 +160,60 @@ static void __attribute((constructor)) init() { } /* - * Return the fd table for this fd or NULL is fd out - * of range. + * Return the fd table for this fd. */ static inline fdEntry_t *getFdEntry(int fd) { - if (fd < 0 || fd >= fdCount) { + fdEntry_t* result = NULL; + + if (fd < 0) { return NULL; } - return &fdTable[fd]; + + /* This should not happen. If it does, our assumption about + * max. fd value was wrong. */ + assert(fd < fdLimit); + + if (fd < fdTableMaxSize) { + /* fd is in base table. */ + assert(fd < fdTableLen); + result = &fdTable[fd]; + } else { + /* fd is in overflow table. */ + const int indexInOverflowTable = fd - fdTableMaxSize; + const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize; + const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize; + fdEntry_t* slab = NULL; + assert(rootindex < fdOverflowTableLen); + assert(slabindex < fdOverflowTableSlabSize); + pthread_mutex_lock(&fdOverflowTableLock); + /* Allocate new slab in overflow table if needed */ + if (fdOverflowTable[rootindex] == NULL) { + fdEntry_t* const newSlab = + (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t)); + if (newSlab == NULL) { + fprintf(stderr, "Unable to allocate file descriptor overflow" + " table slab - out of memory"); + pthread_mutex_unlock(&fdOverflowTableLock); + abort(); + } else { + int i; + for (i = 0; i < fdOverflowTableSlabSize; i ++) { + pthread_mutex_init(&newSlab[i].lock, NULL); + } + fdOverflowTable[rootindex] = newSlab; + } + } + pthread_mutex_unlock(&fdOverflowTableLock); + slab = fdOverflowTable[rootindex]; + result = &slab[slabindex]; + } + + return result; + } + /* * Start a blocking operation :- * Insert thread onto thread list for the fd. From 49b2db4ae7ff6499003679f87df594ba5947ffad Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 18 Mar 2016 18:07:55 -0700 Subject: [PATCH 023/222] 8152335: Improve MethodHandle consistency Co-authored-by: Michael Haupt Reviewed-by: acorn, ahgross, jrose --- .../share/classes/java/lang/ClassLoader.java | 3 + .../classes/java/lang/invoke/MemberName.java | 29 ++++++-- .../java/lang/invoke/MethodHandleNatives.java | 2 +- .../classes/sun/invoke/util/VerifyAccess.java | 68 +++++++++++++++---- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java index 1fcd03b760f..61123302a3c 100644 --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java @@ -817,6 +817,9 @@ public abstract class ClassLoader { if (!checkName(name)) throw new NoClassDefFoundError("IllegalName: " + name); + // Note: Checking logic in java.lang.invoke.MemberName.checkForTypeAlias + // relies on the fact that spoofing is impossible if a class has a name + // of the form "java.*" if ((name != null) && name.startsWith("java.") && this != getBuiltinPlatformClassLoader()) { throw new SecurityException diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java index d141efcac6e..de4e3c15537 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -827,7 +827,7 @@ import java.util.Objects; assert(isResolved() == isResolved); } - void checkForTypeAlias() { + void checkForTypeAlias(Class refc) { if (isInvocable()) { MethodType type; if (this.type instanceof MethodType) @@ -835,16 +835,16 @@ import java.util.Objects; else this.type = type = getMethodType(); if (type.erase() == type) return; - if (VerifyAccess.isTypeVisible(type, clazz)) return; - throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz); + if (VerifyAccess.isTypeVisible(type, refc)) return; + throw new LinkageError("bad method type alias: "+type+" not visible from "+refc); } else { Class type; if (this.type instanceof Class) type = (Class) this.type; else this.type = type = getFieldType(); - if (VerifyAccess.isTypeVisible(type, clazz)) return; - throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz); + if (VerifyAccess.isTypeVisible(type, refc)) return; + throw new LinkageError("bad field type alias: "+type+" not visible from "+refc); } } @@ -1016,10 +1016,25 @@ import java.util.Objects; MemberName m = ref.clone(); // JVM will side-effect the ref assert(refKind == m.getReferenceKind()); try { + // There are 4 entities in play here: + // * LC: lookupClass + // * REFC: symbolic reference class (MN.clazz before resolution); + // * DEFC: resolved method holder (MN.clazz after resolution); + // * PTYPES: parameter types (MN.type) + // + // What we care about when resolving a MemberName is consistency between DEFC and PTYPES. + // We do type alias (TA) checks on DEFC to ensure that. DEFC is not known until the JVM + // finishes the resolution, so do TA checks right after MHN.resolve() is over. + // + // All parameters passed by a caller are checked against MH type (PTYPES) on every invocation, + // so it is safe to call a MH from any context. + // + // REFC view on PTYPES doesn't matter, since it is used only as a starting point for resolution and doesn't + // participate in method selection. m = MethodHandleNatives.resolve(m, lookupClass); - m.checkForTypeAlias(); + m.checkForTypeAlias(m.getDeclaringClass()); m.resolution = null; - } catch (LinkageError ex) { + } catch (ClassNotFoundException | LinkageError ex) { // JVM reports that the "bytecode behavior" would get an error assert(!m.isResolved()); m.resolution = ex; diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java index 7a5d3f1f0b2..67c197dd709 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -49,7 +49,7 @@ class MethodHandleNatives { static native void init(MemberName self, Object ref); static native void expand(MemberName self); - static native MemberName resolve(MemberName self, Class caller) throws LinkageError; + static native MemberName resolve(MemberName self, Class caller) throws LinkageError, ClassNotFoundException; static native int getMembers(Class defc, String matchName, String matchSig, int matchFlags, Class caller, int skip, MemberName[] results); diff --git a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java index 456909fde1c..37cbede912a 100644 --- a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java +++ b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java @@ -231,22 +231,66 @@ public class VerifyAccess { * @param refc the class attempting to make the reference */ public static boolean isTypeVisible(Class type, Class refc) { - if (type == refc) return true; // easy check + if (type == refc) { + return true; // easy check + } while (type.isArray()) type = type.getComponentType(); - if (type.isPrimitive() || type == Object.class) return true; - ClassLoader parent = type.getClassLoader(); - if (parent == null) return true; - ClassLoader child = refc.getClassLoader(); - if (child == null) return false; - if (parent == child || loadersAreRelated(parent, child, true)) + if (type.isPrimitive() || type == Object.class) { return true; - // Do it the hard way: Look up the type name from the refc loader. - try { - Class res = child.loadClass(type.getName()); - return (type == res); - } catch (ClassNotFoundException ex) { + } + ClassLoader typeLoader = type.getClassLoader(); + ClassLoader refcLoader = refc.getClassLoader(); + if (typeLoader == refcLoader) { + return true; + } + if (refcLoader == null && typeLoader != null) { return false; } + if (typeLoader == null && type.getName().startsWith("java.")) { + // Note: The API for actually loading classes, ClassLoader.defineClass, + // guarantees that classes with names beginning "java." cannot be aliased, + // because class loaders cannot load them directly. + return true; + } + + // Do it the hard way: Look up the type name from the refc loader. + // + // Force the refc loader to report and commit to a particular binding for this type name (type.getName()). + // + // In principle, this query might force the loader to load some unrelated class, + // which would cause this query to fail (and the original caller to give up). + // This would be wasted effort, but it is expected to be very rare, occurring + // only when an attacker is attempting to create a type alias. + // In the normal case, one class loader will simply delegate to the other, + // and the same type will be visible through both, with no extra loading. + // + // It is important to go through Class.forName instead of ClassLoader.loadClass + // because Class.forName goes through the JVM system dictionary, which records + // the class lookup once for all. This means that even if a not-well-behaved class loader + // would "change its mind" about the meaning of the name, the Class.forName request + // will use the result cached in the JVM system dictionary. Note that the JVM system dictionary + // will record the first successful result. Unsuccessful results are not stored. + // + // We use doPrivileged in order to allow an unprivileged caller to ask an arbitrary + // class loader about the binding of the proposed name (type.getName()). + // The looked up type ("res") is compared for equality against the proposed + // type ("type") and then is discarded. Thus, the worst that can happen to + // the "child" class loader is that it is bothered to load and report a class + // that differs from "type"; this happens once due to JVM system dictionary + // memoization. And the caller never gets to look at the alternate type binding + // ("res"), whether it exists or not. + final String name = type.getName(); + Class res = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction<>() { + public Class run() { + try { + return Class.forName(name, false, refcLoader); + } catch (ClassNotFoundException | LinkageError e) { + return null; // Assume the class is not found + } + } + }); + return (type == res); } /** From 4b662bba26d584ae0a3d0a536d817aa50104504f Mon Sep 17 00:00:00 2001 From: Andreas Lundblad Date: Mon, 18 Apr 2016 21:07:50 +0200 Subject: [PATCH 024/222] 8036952: copyright issues in jdk9/dev/langtools files Updated copyright notices. Reviewed-by: jjg, jlahoda --- .../com/sun/tools/javac/file/FSInfo.java | 24 +++++++++++++++++++ langtools/test/tools/javac/6520152/T.java | 23 ++++++++++++++++++ .../test/tools/javac/6520152/T6520152.java | 23 ++++++++++++++++++ .../test/tools/javac/6521805/T6521805e.out | 2 +- .../test/tools/javac/6521805/p/Outer.java | 2 ++ langtools/test/tools/javac/6521805/p/Sub.java | 2 ++ langtools/test/tools/javac/6547131/T.java | 23 ++++++++++++++++++ .../test/tools/javac/6589361/T6589361.java | 23 ++++++++++++++++++ .../tools/javac/6668794/badSource/Test.java | 2 +- .../typeAnnotations/referenceinfos/Test.java | 22 +++++++++++++++++ .../tools/javac/api/6731573/Erroneous.java | 2 ++ langtools/test/tools/javac/flow/T8062747.java | 23 ++++++++++++++++++ .../jvm/6397652/com/test/Test$Test$Test.java | 23 ++++++++++++++++++ .../javac/jvm/6397652/com/test/Test$Test.java | 23 ++++++++++++++++++ .../lambda/badMemberRefBytecode/Main.java | 24 +++++++++++++++++++ .../lambda/badMemberRefBytecode/Use.java | 23 ++++++++++++++++++ .../javac/lambda/lambdaExecution/TBlock.java | 23 ++++++++++++++++++ .../test/tools/javac/policy/test3/A.java | 2 ++ .../tools/javac/synthesize/src/Double.java | 23 ++++++++++++++++++ .../tools/javac/synthesize/src/Float.java | 23 ++++++++++++++++++ .../javac/warnings/6594914/Auxiliary.java | 2 ++ .../warnings/6594914/ExplicitCompilation.out | 2 +- .../warnings/6594914/ImplicitCompilation.out | 2 +- langtools/test/tools/javap/4111861/A.java | 23 ++++++++++++++++++ 24 files changed, 360 insertions(+), 4 deletions(-) diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java index 974f28fe5ce..fea4ef7a60a 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java @@ -1,3 +1,27 @@ +/* + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 com.sun.tools.javac.file; diff --git a/langtools/test/tools/javac/6520152/T.java b/langtools/test/tools/javac/6520152/T.java index 8a46b8f5735..8443a4dc50e 100644 --- a/langtools/test/tools/javac/6520152/T.java +++ b/langtools/test/tools/javac/6520152/T.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.Serializable; public class T { diff --git a/langtools/test/tools/javac/6520152/T6520152.java b/langtools/test/tools/javac/6520152/T6520152.java index bdb15990296..c7cbf31eb95 100644 --- a/langtools/test/tools/javac/6520152/T6520152.java +++ b/langtools/test/tools/javac/6520152/T6520152.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6520152 diff --git a/langtools/test/tools/javac/6521805/T6521805e.out b/langtools/test/tools/javac/6521805/T6521805e.out index 04c71cd8821..31b628ce2d6 100644 --- a/langtools/test/tools/javac/6521805/T6521805e.out +++ b/langtools/test/tools/javac/6521805/T6521805e.out @@ -1,2 +1,2 @@ -Sub.java:8:11: compiler.err.synthetic.name.conflict: this$0, p.Inner +Sub.java:10:11: compiler.err.synthetic.name.conflict: this$0, p.Inner 1 error diff --git a/langtools/test/tools/javac/6521805/p/Outer.java b/langtools/test/tools/javac/6521805/p/Outer.java index 3dd1de56b78..8a92158426b 100644 --- a/langtools/test/tools/javac/6521805/p/Outer.java +++ b/langtools/test/tools/javac/6521805/p/Outer.java @@ -1,3 +1,5 @@ +/* /nodynamiccopyright/ */ + package p; class Outer { diff --git a/langtools/test/tools/javac/6521805/p/Sub.java b/langtools/test/tools/javac/6521805/p/Sub.java index 7a9f78896e3..a6d00c76a6d 100644 --- a/langtools/test/tools/javac/6521805/p/Sub.java +++ b/langtools/test/tools/javac/6521805/p/Sub.java @@ -1,3 +1,5 @@ +/* /nodynamiccopyright/ */ + package p; class Inner extends Outer.Super { diff --git a/langtools/test/tools/javac/6547131/T.java b/langtools/test/tools/javac/6547131/T.java index 76d8a5b344f..5acf9b2ae63 100644 --- a/langtools/test/tools/javac/6547131/T.java +++ b/langtools/test/tools/javac/6547131/T.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6547131 diff --git a/langtools/test/tools/javac/6589361/T6589361.java b/langtools/test/tools/javac/6589361/T6589361.java index 4d405e41d21..5a69bc5ec99 100644 --- a/langtools/test/tools/javac/6589361/T6589361.java +++ b/langtools/test/tools/javac/6589361/T6589361.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6589361 diff --git a/langtools/test/tools/javac/6668794/badSource/Test.java b/langtools/test/tools/javac/6668794/badSource/Test.java index 162493e5ab1..c683bbe7f48 100644 --- a/langtools/test/tools/javac/6668794/badSource/Test.java +++ b/langtools/test/tools/javac/6668794/badSource/Test.java @@ -1,5 +1,5 @@ /* - * @test /nodynamiccopyight/ + * @test /nodynamiccopyright/ * @bug 6668794 6668796 * @summary javac puts localized text in raw diagnostics * bad diagnostic "bad class file" given for source files diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Test.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Test.java index b6cb1cae604..811bbbf454b 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Test.java +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Test.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.*; import java.lang.annotation.*; diff --git a/langtools/test/tools/javac/api/6731573/Erroneous.java b/langtools/test/tools/javac/api/6731573/Erroneous.java index 7902f871c95..4bc66258016 100644 --- a/langtools/test/tools/javac/api/6731573/Erroneous.java +++ b/langtools/test/tools/javac/api/6731573/Erroneous.java @@ -1,3 +1,5 @@ +/* /nodynamiccopyright/ */ + class A { boolean b; boolean b; diff --git a/langtools/test/tools/javac/flow/T8062747.java b/langtools/test/tools/javac/flow/T8062747.java index 857474216d5..8d2cfd17abc 100644 --- a/langtools/test/tools/javac/flow/T8062747.java +++ b/langtools/test/tools/javac/flow/T8062747.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8062747 diff --git a/langtools/test/tools/javac/jvm/6397652/com/test/Test$Test$Test.java b/langtools/test/tools/javac/jvm/6397652/com/test/Test$Test$Test.java index 83a81213721..6be3c7d93ac 100644 --- a/langtools/test/tools/javac/jvm/6397652/com/test/Test$Test$Test.java +++ b/langtools/test/tools/javac/jvm/6397652/com/test/Test$Test$Test.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package com.test; public class Test$Test$Test { diff --git a/langtools/test/tools/javac/jvm/6397652/com/test/Test$Test.java b/langtools/test/tools/javac/jvm/6397652/com/test/Test$Test.java index d15532570b1..f439128a987 100644 --- a/langtools/test/tools/javac/jvm/6397652/com/test/Test$Test.java +++ b/langtools/test/tools/javac/jvm/6397652/com/test/Test$Test.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package com.test; public class Test$Test { diff --git a/langtools/test/tools/javac/lambda/badMemberRefBytecode/Main.java b/langtools/test/tools/javac/lambda/badMemberRefBytecode/Main.java index 4c834cf3741..a188c4a74af 100644 --- a/langtools/test/tools/javac/lambda/badMemberRefBytecode/Main.java +++ b/langtools/test/tools/javac/lambda/badMemberRefBytecode/Main.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.Collections; public class Main { @@ -6,4 +29,5 @@ public class Main { Collections.sort(null, String::compareTo); } + } diff --git a/langtools/test/tools/javac/lambda/badMemberRefBytecode/Use.java b/langtools/test/tools/javac/lambda/badMemberRefBytecode/Use.java index bb5a77a06ef..fa89e8118b1 100644 --- a/langtools/test/tools/javac/lambda/badMemberRefBytecode/Use.java +++ b/langtools/test/tools/javac/lambda/badMemberRefBytecode/Use.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 Use { private Main m; } diff --git a/langtools/test/tools/javac/lambda/lambdaExecution/TBlock.java b/langtools/test/tools/javac/lambda/lambdaExecution/TBlock.java index 329eaf25de1..48d56c9f403 100644 --- a/langtools/test/tools/javac/lambda/lambdaExecution/TBlock.java +++ b/langtools/test/tools/javac/lambda/lambdaExecution/TBlock.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + /** * Performs operations upon an input object which may modify that object and/or * external state (other objects). diff --git a/langtools/test/tools/javac/policy/test3/A.java b/langtools/test/tools/javac/policy/test3/A.java index b21c7713860..c1f4c63bf88 100644 --- a/langtools/test/tools/javac/policy/test3/A.java +++ b/langtools/test/tools/javac/policy/test3/A.java @@ -1,3 +1,5 @@ +/* /nodynamiccopyright/ */ + class A { void m1() { System.err.println("hello"); diff --git a/langtools/test/tools/javac/synthesize/src/Double.java b/langtools/test/tools/javac/synthesize/src/Double.java index 7ae620e85c8..b4cf0392933 100644 --- a/langtools/test/tools/javac/synthesize/src/Double.java +++ b/langtools/test/tools/javac/synthesize/src/Double.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package java.lang; public class Double extends Number diff --git a/langtools/test/tools/javac/synthesize/src/Float.java b/langtools/test/tools/javac/synthesize/src/Float.java index afbef38bebc..4b2fb18d5a6 100644 --- a/langtools/test/tools/javac/synthesize/src/Float.java +++ b/langtools/test/tools/javac/synthesize/src/Float.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package java.lang; public class Float extends Number diff --git a/langtools/test/tools/javac/warnings/6594914/Auxiliary.java b/langtools/test/tools/javac/warnings/6594914/Auxiliary.java index e9c881643e2..19157042e8e 100644 --- a/langtools/test/tools/javac/warnings/6594914/Auxiliary.java +++ b/langtools/test/tools/javac/warnings/6594914/Auxiliary.java @@ -1,3 +1,5 @@ +/* /nodynamiccopyright/ */ + import java.io.StringBufferInputStream; public class Auxiliary { diff --git a/langtools/test/tools/javac/warnings/6594914/ExplicitCompilation.out b/langtools/test/tools/javac/warnings/6594914/ExplicitCompilation.out index 3dff7922cf7..abb4822197b 100644 --- a/langtools/test/tools/javac/warnings/6594914/ExplicitCompilation.out +++ b/langtools/test/tools/javac/warnings/6594914/ExplicitCompilation.out @@ -1,2 +1,2 @@ -Auxiliary.java:1:15: compiler.warn.has.been.deprecated: java.io.StringBufferInputStream, java.io +Auxiliary.java:3:15: compiler.warn.has.been.deprecated: java.io.StringBufferInputStream, java.io 1 warning diff --git a/langtools/test/tools/javac/warnings/6594914/ImplicitCompilation.out b/langtools/test/tools/javac/warnings/6594914/ImplicitCompilation.out index 3dff7922cf7..abb4822197b 100644 --- a/langtools/test/tools/javac/warnings/6594914/ImplicitCompilation.out +++ b/langtools/test/tools/javac/warnings/6594914/ImplicitCompilation.out @@ -1,2 +1,2 @@ -Auxiliary.java:1:15: compiler.warn.has.been.deprecated: java.io.StringBufferInputStream, java.io +Auxiliary.java:3:15: compiler.warn.has.been.deprecated: java.io.StringBufferInputStream, java.io 1 warning diff --git a/langtools/test/tools/javap/4111861/A.java b/langtools/test/tools/javap/4111861/A.java index 32cc86a8f07..3abd02c6b8a 100644 --- a/langtools/test/tools/javap/4111861/A.java +++ b/langtools/test/tools/javap/4111861/A.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + class A { public static final int i = 42; public static final boolean b = true; From 9691505077918e937d7315a606e8ebf1648bec60 Mon Sep 17 00:00:00 2001 From: Andreas Lundblad Date: Mon, 18 Apr 2016 22:25:50 +0200 Subject: [PATCH 025/222] 7152104: javac should not warn about missing serialVersionUID for anonymous inner classes Javac no longer issues warnings for missing serialVersionUID in anonymous classes. Reviewed-by: jlahoda --- .../com/sun/tools/javac/comp/Attr.java | 9 ++--- langtools/test/tools/javac/T6554097.java | 21 ++++++----- langtools/test/tools/javac/T6554097.out | 22 +++++++++--- .../javac/diags/examples/AnonymousClass.java | 13 ++++--- .../test/tools/javac/positions/T6253161.java | 36 ------------------- .../test/tools/javac/positions/T6253161.out | 2 -- .../test/tools/javac/positions/T6253161a.java | 28 --------------- .../test/tools/javac/positions/T6253161a.out | 2 -- .../tools/javac/{ => serial}/SerialWarn.java | 0 .../tools/javac/{ => serial}/SerialWarn.out | 0 .../tools/javac/serial/SerialWarnAnon.java | 15 ++++++++ 11 files changed, 57 insertions(+), 91 deletions(-) delete mode 100644 langtools/test/tools/javac/positions/T6253161.java delete mode 100644 langtools/test/tools/javac/positions/T6253161.out delete mode 100644 langtools/test/tools/javac/positions/T6253161a.java delete mode 100644 langtools/test/tools/javac/positions/T6253161a.out rename langtools/test/tools/javac/{ => serial}/SerialWarn.java (100%) rename langtools/test/tools/javac/{ => serial}/SerialWarn.out (100%) create mode 100644 langtools/test/tools/javac/serial/SerialWarnAnon.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index ccbe70acfbd..1fd1d379a74 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -4491,10 +4491,11 @@ public class Attr extends JCTree.Visitor { chk.checkNonCyclicElements(tree); // Check for proper use of serialVersionUID - if (env.info.lint.isEnabled(LintCategory.SERIAL) && - isSerializable(c.type) && - (c.flags() & Flags.ENUM) == 0 && - checkForSerial(c)) { + if (env.info.lint.isEnabled(LintCategory.SERIAL) + && isSerializable(c.type) + && (c.flags() & Flags.ENUM) == 0 + && !c.isAnonymous() + && checkForSerial(c)) { checkSerialVersionUID(tree, c); } if (allowTypeAnnos) { diff --git a/langtools/test/tools/javac/T6554097.java b/langtools/test/tools/javac/T6554097.java index 4deb2e9b5a8..076517c7140 100644 --- a/langtools/test/tools/javac/T6554097.java +++ b/langtools/test/tools/javac/T6554097.java @@ -3,24 +3,27 @@ * @bug 6554097 * @summary "final" confuses at-SuppressWarnings * @compile T6554097.java - * @compile/fail/ref=T6554097.out -XDrawDiagnostics -Werror -Xlint:serial T6554097.java + * @compile/fail/ref=T6554097.out -XDrawDiagnostics -Werror -Xlint:rawtypes T6554097.java */ +import java.util.ArrayList; + class T6554097 { - @SuppressWarnings("serial") final Throwable[] v1 = { new Throwable() {} }; - @SuppressWarnings("serial") Throwable[] v2 = { new Throwable() {} }; + + @SuppressWarnings("unchecked") final ArrayList[] v1 = { new ArrayList() {} }; + @SuppressWarnings("unchecked") ArrayList[] v2 = { new ArrayList() {} }; public static void m1() throws Throwable { - @SuppressWarnings("serial") final Throwable[] v3 = { new Throwable() {} }; - @SuppressWarnings("serial") Throwable[] v4 = { new Throwable() {} }; + @SuppressWarnings("unchecked") final ArrayList[] v3 = { new ArrayList() {} }; + @SuppressWarnings("unchecked") ArrayList[] v4 = { new ArrayList() {} }; } - final Throwable[] v5 = { new Throwable() {} }; - Throwable[] v6 = { new Throwable() {} }; + final ArrayList[] v5 = { new ArrayList() {} }; + ArrayList[] v6 = { new ArrayList() {} }; public static void m2() throws Throwable { - final Throwable[] v7 = { new Throwable() {} }; - Throwable[] v8 = { new Throwable() {} }; + final ArrayList[] v7 = { new ArrayList() {} }; + ArrayList[] v8 = { new ArrayList() {} }; } } diff --git a/langtools/test/tools/javac/T6554097.out b/langtools/test/tools/javac/T6554097.out index aecbd999cf5..14db8a54b81 100644 --- a/langtools/test/tools/javac/T6554097.out +++ b/langtools/test/tools/javac/T6554097.out @@ -1,7 +1,19 @@ -T6554097.java:18:46: compiler.warn.missing.SVUID: compiler.misc.anonymous.class: T6554097$5 -T6554097.java:19:46: compiler.warn.missing.SVUID: compiler.misc.anonymous.class: T6554097$6 -T6554097.java:22:50: compiler.warn.missing.SVUID: compiler.misc.anonymous.class: T6554097$7 -T6554097.java:23:54: compiler.warn.missing.SVUID: compiler.misc.anonymous.class: T6554097$8 +T6554097.java:13:42: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:13:65: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:14:42: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:14:65: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:17:50: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:17:73: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:18:50: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:18:73: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:21:11: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:21:34: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:22:11: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:22:34: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:25:15: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:25:38: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:26:15: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList +T6554097.java:26:38: compiler.warn.raw.class.use: java.util.ArrayList, java.util.ArrayList - compiler.err.warnings.and.werror 1 error -4 warnings +16 warnings diff --git a/langtools/test/tools/javac/diags/examples/AnonymousClass.java b/langtools/test/tools/javac/diags/examples/AnonymousClass.java index 771d888ddbc..d5e3858f13a 100644 --- a/langtools/test/tools/javac/diags/examples/AnonymousClass.java +++ b/langtools/test/tools/javac/diags/examples/AnonymousClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,12 +22,15 @@ */ // key: compiler.misc.anonymous.class -// key: compiler.warn.missing.SVUID -// options: -Xlint:serial +// key: compiler.err.prob.found.req +// key: compiler.misc.inconvertible.types +// options: -Xlint:rawtypes // run: simple +import java.util.ArrayList; + class AnonymousClass { - Exception m() { - return new Exception() { }; + Object m() { + return (ArrayList) new ArrayList() { }; } } diff --git a/langtools/test/tools/javac/positions/T6253161.java b/langtools/test/tools/javac/positions/T6253161.java deleted file mode 100644 index 5824a457707..00000000000 --- a/langtools/test/tools/javac/positions/T6253161.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * @test /nodynamiccopyright/ - * @bug 6253161 - * @summary Compiler will fail to find the correct location of serial warnings for anonymous inner classes - * @author Seetharama Avadhanam - * @compile -Xlint:serial -XDdev T6253161.java - * @compile/ref=T6253161.out -Xlint:serial -XDdev -XDrawDiagnostics T6253161.java - */ -import java.util.List; -import java.util.ArrayList; - -public class T6253161 { - @SuppressWarnings("unchecked") - public void anonymousMethod(){ - List list = new ArrayList(){ - static final long serialVersionUID = 1; - List list = new ArrayList(); - public List getMyList(){ - final List floatList = new ArrayList(){ - List integerList = new ArrayList(); - public List getMyList(){ - for(int i=0;i<10;i++) - integerList.add((int)((Float.parseFloat(i+""))+(1.11F))); - return (List)(Object)integerList; - } - public void testMethods(){ - //... - } - }.getMyList(); - for(int i=0;i<10;i++) - list.add((Float)(floatList.get(i)) * 11.232F * i); - return list; - } - }.getMyList(); - } -} diff --git a/langtools/test/tools/javac/positions/T6253161.out b/langtools/test/tools/javac/positions/T6253161.out deleted file mode 100644 index d5d2e5162e8..00000000000 --- a/langtools/test/tools/javac/positions/T6253161.out +++ /dev/null @@ -1,2 +0,0 @@ -T6253161.java:19:62: compiler.warn.missing.SVUID: compiler.misc.anonymous.class: T6253161$1$1 -1 warning diff --git a/langtools/test/tools/javac/positions/T6253161a.java b/langtools/test/tools/javac/positions/T6253161a.java deleted file mode 100644 index 1adfd72f8a9..00000000000 --- a/langtools/test/tools/javac/positions/T6253161a.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * @test /nodynamiccopyright/ - * @bug 6253161 - * @summary Compiler will fail to find the correct location of serial warnings for anonymous inner classes - * @author Seetharama Avadhanam - * @compile -Xlint:serial -XDdev T6253161a.java - * @compile/ref=T6253161a.out -Xlint:serial -XDdev -XDrawDiagnostics T6253161a.java - */ -import java.util.List; -import java.util.ArrayList; - -public class T6253161a { - @SuppressWarnings("unchecked") - public void anonymousMethod(){ - List list = new ArrayList(){ - static final long serialVersionUID = 1; - List list = new ArrayList(); - public List getMyList(){ - final List floatList = new ArrayList(){ - // Blank .... - }; - for(int i=0;i<10;i++) - list.add((Float)(floatList.get(i)) * 11.232F * i); - return list; - } - }.getMyList(); - } -} diff --git a/langtools/test/tools/javac/positions/T6253161a.out b/langtools/test/tools/javac/positions/T6253161a.out deleted file mode 100644 index e5ba714cb51..00000000000 --- a/langtools/test/tools/javac/positions/T6253161a.out +++ /dev/null @@ -1,2 +0,0 @@ -T6253161a.java:19:62: compiler.warn.missing.SVUID: compiler.misc.anonymous.class: T6253161a$1$1 -1 warning diff --git a/langtools/test/tools/javac/SerialWarn.java b/langtools/test/tools/javac/serial/SerialWarn.java similarity index 100% rename from langtools/test/tools/javac/SerialWarn.java rename to langtools/test/tools/javac/serial/SerialWarn.java diff --git a/langtools/test/tools/javac/SerialWarn.out b/langtools/test/tools/javac/serial/SerialWarn.out similarity index 100% rename from langtools/test/tools/javac/SerialWarn.out rename to langtools/test/tools/javac/serial/SerialWarn.out diff --git a/langtools/test/tools/javac/serial/SerialWarnAnon.java b/langtools/test/tools/javac/serial/SerialWarnAnon.java new file mode 100644 index 00000000000..2e6def59519 --- /dev/null +++ b/langtools/test/tools/javac/serial/SerialWarnAnon.java @@ -0,0 +1,15 @@ +/* + * @test /nodynamiccopyright/ + * @bug 7152104 + * @summary Make sure no warning is emitted for anonymous classes + * without serialVersionUID + * @compile SerialWarn.java + * @compile -Werror -XDrawDiagnostics -Xlint:serial SerialWarnAnon.java + */ + +class SerialWarnAnon { + interface SerialWarnAnonInterface extends java.io.Serializable { } + Object m() { + return new SerialWarnAnonInterface() { }; + } +} From 2d863bcd37bcbd06e39559add140e9d2cde73f5e Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Mon, 18 Apr 2016 14:04:09 -0700 Subject: [PATCH 026/222] 8145468: update java.lang APIs with new deprecations Reviewed-by: mcimadamore --- .../com/sun/tools/javac/comp/ConstFold.java | 50 +++++++++---------- .../com/sun/tools/javac/jvm/ClassReader.java | 6 +-- .../classes/com/sun/tools/javac/jvm/Gen.java | 2 +- .../sun/tools/javac/parser/JavacParser.java | 2 +- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java index be33a96ffc6..3436c18ceaf 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java @@ -125,15 +125,15 @@ strictfp class ConstFold { return syms.booleanType.constType(b2i(intValue(od) >= 0)); case lneg: // unary - - return syms.longType.constType(new Long(-longValue(od))); + return syms.longType.constType(Long.valueOf(-longValue(od))); case lxor: // ~ - return syms.longType.constType(new Long(~longValue(od))); + return syms.longType.constType(Long.valueOf(~longValue(od))); case fneg: // unary - - return syms.floatType.constType(new Float(-floatValue(od))); + return syms.floatType.constType(Float.valueOf(-floatValue(od))); case dneg: // ~ - return syms.doubleType.constType(new Double(-doubleValue(od))); + return syms.doubleType.constType(Double.valueOf(-doubleValue(od))); default: return null; @@ -216,37 +216,37 @@ strictfp class ConstFold { case ladd: return syms.longType.constType( - new Long(longValue(l) + longValue(r))); + Long.valueOf(longValue(l) + longValue(r))); case lsub: return syms.longType.constType( - new Long(longValue(l) - longValue(r))); + Long.valueOf(longValue(l) - longValue(r))); case lmul: return syms.longType.constType( - new Long(longValue(l) * longValue(r))); + Long.valueOf(longValue(l) * longValue(r))); case ldiv: return syms.longType.constType( - new Long(longValue(l) / longValue(r))); + Long.valueOf(longValue(l) / longValue(r))); case lmod: return syms.longType.constType( - new Long(longValue(l) % longValue(r))); + Long.valueOf(longValue(l) % longValue(r))); case land: return syms.longType.constType( - new Long(longValue(l) & longValue(r))); + Long.valueOf(longValue(l) & longValue(r))); case lor: return syms.longType.constType( - new Long(longValue(l) | longValue(r))); + Long.valueOf(longValue(l) | longValue(r))); case lxor: return syms.longType.constType( - new Long(longValue(l) ^ longValue(r))); + Long.valueOf(longValue(l) ^ longValue(r))); case lshl: case lshll: return syms.longType.constType( - new Long(longValue(l) << intValue(r))); + Long.valueOf(longValue(l) << intValue(r))); case lshr: case lshrl: return syms.longType.constType( - new Long(longValue(l) >> intValue(r))); + Long.valueOf(longValue(l) >> intValue(r))); case lushr: return syms.longType.constType( - new Long(longValue(l) >>> intValue(r))); + Long.valueOf(longValue(l) >>> intValue(r))); case lcmp: if (longValue(l) < longValue(r)) return syms.intType.constType(minusOne); @@ -256,19 +256,19 @@ strictfp class ConstFold { return syms.intType.constType(zero); case fadd: return syms.floatType.constType( - new Float(floatValue(l) + floatValue(r))); + Float.valueOf(floatValue(l) + floatValue(r))); case fsub: return syms.floatType.constType( - new Float(floatValue(l) - floatValue(r))); + Float.valueOf(floatValue(l) - floatValue(r))); case fmul: return syms.floatType.constType( - new Float(floatValue(l) * floatValue(r))); + Float.valueOf(floatValue(l) * floatValue(r))); case fdiv: return syms.floatType.constType( - new Float(floatValue(l) / floatValue(r))); + Float.valueOf(floatValue(l) / floatValue(r))); case fmod: return syms.floatType.constType( - new Float(floatValue(l) % floatValue(r))); + Float.valueOf(floatValue(l) % floatValue(r))); case fcmpg: case fcmpl: if (floatValue(l) < floatValue(r)) return syms.intType.constType(minusOne); @@ -282,19 +282,19 @@ strictfp class ConstFold { return syms.intType.constType(minusOne); case dadd: return syms.doubleType.constType( - new Double(doubleValue(l) + doubleValue(r))); + Double.valueOf(doubleValue(l) + doubleValue(r))); case dsub: return syms.doubleType.constType( - new Double(doubleValue(l) - doubleValue(r))); + Double.valueOf(doubleValue(l) - doubleValue(r))); case dmul: return syms.doubleType.constType( - new Double(doubleValue(l) * doubleValue(r))); + Double.valueOf(doubleValue(l) * doubleValue(r))); case ddiv: return syms.doubleType.constType( - new Double(doubleValue(l) / doubleValue(r))); + Double.valueOf(doubleValue(l) / doubleValue(r))); case dmod: return syms.doubleType.constType( - new Double(doubleValue(l) % doubleValue(r))); + Double.valueOf(doubleValue(l) % doubleValue(r))); case dcmpg: case dcmpl: if (doubleValue(l) < doubleValue(r)) return syms.intType.constType(minusOne); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 9806e85f959..12c46059519 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -457,13 +457,13 @@ public class ClassReader { poolObj[i] = getInt(index + 1); break; case CONSTANT_Float: - poolObj[i] = new Float(getFloat(index + 1)); + poolObj[i] = Float.valueOf(getFloat(index + 1)); break; case CONSTANT_Long: - poolObj[i] = new Long(getLong(index + 1)); + poolObj[i] = Long.valueOf(getLong(index + 1)); break; case CONSTANT_Double: - poolObj[i] = new Double(getDouble(index + 1)); + poolObj[i] = Double.valueOf(getDouble(index + 1)); break; case CONSTANT_MethodHandle: skipBytes(4); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index b551b61e8d9..5de84f0ab59 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -203,7 +203,7 @@ public class Gen extends JCTree.Visitor { */ void emitMinusOne(int tc) { if (tc == LONGcode) { - items.makeImmediateItem(syms.longType, new Long(-1)).load(); + items.makeImmediateItem(syms.longType, Long.valueOf(-1)).load(); } else { code.emitop0(iconst_m1); } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index c0b69a9c86e..e6e3b839e25 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -686,7 +686,7 @@ public class JavacParser implements Parser { try { t = F.at(pos).Literal( TypeTag.LONG, - new Long(Convert.string2long(strval(prefix), token.radix()))); + Long.valueOf(Convert.string2long(strval(prefix), token.radix()))); } catch (NumberFormatException ex) { error(token.pos, "int.number.too.large", strval(prefix)); } From 8f62cdc8a03baaacac556edde84a7a01ba58cd62 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Mon, 18 Apr 2016 18:41:38 -0700 Subject: [PATCH 027/222] 8154504: javac tests fail after JDK API is deprecated Reviewed-by: darcy --- langtools/test/tools/javac/CaptureInSubtype.java | 2 +- langtools/test/tools/javac/OverrideChecks/T4721069.java | 2 +- langtools/test/tools/javac/generics/Nonlinear.java | 2 +- langtools/test/tools/javac/generics/odersky/BadTest4.java | 2 +- langtools/test/tools/javac/lambda/8074381/T8074381a.java | 2 ++ langtools/test/tools/javac/lambda/8074381/T8074381a.out | 4 ++-- langtools/test/tools/javac/lambda/TargetType27.java | 2 +- 7 files changed, 9 insertions(+), 7 deletions(-) diff --git a/langtools/test/tools/javac/CaptureInSubtype.java b/langtools/test/tools/javac/CaptureInSubtype.java index 41d5a3b0b1b..3b73e20a6dd 100644 --- a/langtools/test/tools/javac/CaptureInSubtype.java +++ b/langtools/test/tools/javac/CaptureInSubtype.java @@ -33,7 +33,7 @@ public class CaptureInSubtype { public static class ShowFlaw extends SuperOfShowFlaw { - static Flaw fn = new Flaw(new Integer(3)); + static Flaw fn = new Flaw(Integer.valueOf(3)); Flaw m(){return fn;} } diff --git a/langtools/test/tools/javac/OverrideChecks/T4721069.java b/langtools/test/tools/javac/OverrideChecks/T4721069.java index 18259f791d4..ea8f4da567d 100644 --- a/langtools/test/tools/javac/OverrideChecks/T4721069.java +++ b/langtools/test/tools/javac/OverrideChecks/T4721069.java @@ -12,7 +12,7 @@ interface I { static class T { static void f(I i) { if (i == null) { - Integer x = new Integer(2); + Integer x = Integer.valueOf(2); } else { I x = i; x.getClass(); diff --git a/langtools/test/tools/javac/generics/Nonlinear.java b/langtools/test/tools/javac/generics/Nonlinear.java index f952d74c300..36004a07907 100644 --- a/langtools/test/tools/javac/generics/Nonlinear.java +++ b/langtools/test/tools/javac/generics/Nonlinear.java @@ -22,7 +22,7 @@ public class Nonlinear { // the program. public static void main (String [] args) { - Integer x = new Integer (5); + Integer x = Integer.valueOf(5); String y = castit (x); System.out.println (y); } diff --git a/langtools/test/tools/javac/generics/odersky/BadTest4.java b/langtools/test/tools/javac/generics/odersky/BadTest4.java index 1ad3e576b0c..516318d8147 100644 --- a/langtools/test/tools/javac/generics/odersky/BadTest4.java +++ b/langtools/test/tools/javac/generics/odersky/BadTest4.java @@ -30,7 +30,7 @@ class BadTest4 { static Cell makeCell(A x) { return new Cell(x); } static A id(A x) { return x; } - static Integer i = new Integer(1); + static Integer i = Integer.valueOf(1); static Number n = i; public static void main(String[] args) { diff --git a/langtools/test/tools/javac/lambda/8074381/T8074381a.java b/langtools/test/tools/javac/lambda/8074381/T8074381a.java index 7b7b9dd6cc2..d11944d3926 100644 --- a/langtools/test/tools/javac/lambda/8074381/T8074381a.java +++ b/langtools/test/tools/javac/lambda/8074381/T8074381a.java @@ -13,6 +13,7 @@ class T8074381a { boolean m(String s); } + @SuppressWarnings("deprecation") void testRaw() { Sub s1 = c -> true; Sub s2 = Boolean::new; @@ -22,6 +23,7 @@ class T8074381a { }; } + @SuppressWarnings("deprecation") void testNonRaw() { Sub s1 = c -> true; Sub s2 = Boolean::new; diff --git a/langtools/test/tools/javac/lambda/8074381/T8074381a.out b/langtools/test/tools/javac/lambda/8074381/T8074381a.out index f7ba487c586..d969c59a919 100644 --- a/langtools/test/tools/javac/lambda/8074381/T8074381a.out +++ b/langtools/test/tools/javac/lambda/8074381/T8074381a.out @@ -1,4 +1,4 @@ -T8074381a.java:17:18: compiler.err.prob.found.req: (compiler.misc.no.suitable.functional.intf.inst: T8074381a.Sub) T8074381a.java:18:18: compiler.err.prob.found.req: (compiler.misc.no.suitable.functional.intf.inst: T8074381a.Sub) -T8074381a.java:19:28: compiler.err.does.not.override.abstract: compiler.misc.anonymous.class: T8074381a$1, m(java.lang.Object), T8074381a.Sup +T8074381a.java:19:18: compiler.err.prob.found.req: (compiler.misc.no.suitable.functional.intf.inst: T8074381a.Sub) +T8074381a.java:20:28: compiler.err.does.not.override.abstract: compiler.misc.anonymous.class: T8074381a$1, m(java.lang.Object), T8074381a.Sup 3 errors diff --git a/langtools/test/tools/javac/lambda/TargetType27.java b/langtools/test/tools/javac/lambda/TargetType27.java index 762a4ab8bef..dcb76901c7e 100644 --- a/langtools/test/tools/javac/lambda/TargetType27.java +++ b/langtools/test/tools/javac/lambda/TargetType27.java @@ -15,6 +15,6 @@ class TargetType27 { F m(F f) { return null; } void test() { - m((String s1) -> (String s2) -> new Integer(1)); + m((String s1) -> (String s2) -> Integer.valueOf(1)); } } From 28ed819ae90b622f2eedaaceb41a798a8c6af080 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Mon, 18 Apr 2016 19:14:50 -0700 Subject: [PATCH 028/222] 8154500: fix handling of jdk.launcher.patch.* in tests Reviewed-by: ksrini --- .../javadoc/tool/6964914/TestStdDoclet.java | 19 +++++++++++++----- .../javadoc/tool/6964914/TestUserDoclet.java | 19 ++++++++++++++---- .../tools/javadoc/6964914/TestStdDoclet.java | 19 +++++++++++++----- .../tools/javadoc/6964914/TestUserDoclet.java | 20 ++++++++++++++----- 4 files changed, 58 insertions(+), 19 deletions(-) diff --git a/langtools/test/jdk/javadoc/tool/6964914/TestStdDoclet.java b/langtools/test/jdk/javadoc/tool/6964914/TestStdDoclet.java index 3fff0e1252d..3803a5241e9 100644 --- a/langtools/test/jdk/javadoc/tool/6964914/TestStdDoclet.java +++ b/langtools/test/jdk/javadoc/tool/6964914/TestStdDoclet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ */ import java.io.*; +import java.util.*; /** * Dummy javadoc comment. @@ -54,13 +55,21 @@ public class TestStdDoclet { // run javadoc in separate process to ensure doclet executed under // normal user conditions w.r.t. classloader String thisClassName = TestStdDoclet.class.getName(); - Process p = new ProcessBuilder() - .command(javadoc.getPath(), - "-J-Xpatch:" + System.getProperty("jdk.launcher.patch.0", ""), + List cmdArgs = new ArrayList<>(); + cmdArgs.add(javadoc.getPath()); + int i = 0; + String prop; + while ((prop = System.getProperty("jdk.launcher.patch." + (i++))) != null) { + cmdArgs.add("-J-Xpatch:" + prop); + } + cmdArgs.addAll(Arrays.asList( "-classpath", ".", // insulates us from ambient classpath "-Xdoclint:none", "-package", - new File(testSrc, thisClassName + ".java").getPath()) + new File(testSrc, thisClassName + ".java").getPath() + )); + Process p = new ProcessBuilder() + .command(cmdArgs) .redirectErrorStream(true) .start(); diff --git a/langtools/test/jdk/javadoc/tool/6964914/TestUserDoclet.java b/langtools/test/jdk/javadoc/tool/6964914/TestUserDoclet.java index cec6d274d24..02c6ec882b3 100644 --- a/langtools/test/jdk/javadoc/tool/6964914/TestUserDoclet.java +++ b/langtools/test/jdk/javadoc/tool/6964914/TestUserDoclet.java @@ -30,7 +30,10 @@ import java.io.*; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.Set; @@ -63,12 +66,20 @@ public class TestUserDoclet implements Doclet { // run javadoc in separate process to ensure doclet executed under // normal user conditions w.r.t. classloader String thisClassName = TestUserDoclet.class.getName(); - Process p = new ProcessBuilder() - .command(javadoc.getPath(), - "-J-Xpatch:" + System.getProperty("jdk.launcher.patch.0", ""), + List cmdArgs = new ArrayList<>(); + cmdArgs.add(javadoc.getPath()); + int i = 0; + String prop; + while ((prop = System.getProperty("jdk.launcher.patch." + (i++))) != null) { + cmdArgs.add("-J-Xpatch:" + prop); + } + cmdArgs.addAll(Arrays.asList( "-doclet", thisClassName, "-docletpath", testClasses.getPath(), - new File(testSrc, thisClassName + ".java").getPath()) + new File(testSrc, thisClassName + ".java").getPath() + )); + Process p = new ProcessBuilder() + .command(cmdArgs) .redirectErrorStream(true) .start(); diff --git a/langtools/test/tools/javadoc/6964914/TestStdDoclet.java b/langtools/test/tools/javadoc/6964914/TestStdDoclet.java index d30ae8322ff..2ab14c0124c 100644 --- a/langtools/test/tools/javadoc/6964914/TestStdDoclet.java +++ b/langtools/test/tools/javadoc/6964914/TestStdDoclet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ */ import java.io.*; +import java.util.*; /** * Dummy javadoc comment. @@ -54,13 +55,21 @@ public class TestStdDoclet { // run javadoc in separate process to ensure doclet executed under // normal user conditions w.r.t. classloader String thisClassName = TestStdDoclet.class.getName(); - Process p = new ProcessBuilder() - .command(javadoc.getPath(), - "-J-Xpatch:" + System.getProperty("jdk.launcher.patch.0", ""), + List cmdArgs = new ArrayList<>(); + cmdArgs.add(javadoc.getPath()); + int i = 0; + String prop; + while ((prop = System.getProperty("jdk.launcher.patch." + (i++))) != null) { + cmdArgs.add("-J-Xpatch:" + prop); + } + cmdArgs.addAll(Arrays.asList( "-classpath", ".", // insulates us from ambient classpath "-Xdoclint:none", "-package", - new File(testSrc, thisClassName + ".java").getPath()) + new File(testSrc, thisClassName + ".java").getPath() + )); + Process p = new ProcessBuilder() + .command(cmdArgs) .redirectErrorStream(true) .start(); diff --git a/langtools/test/tools/javadoc/6964914/TestUserDoclet.java b/langtools/test/tools/javadoc/6964914/TestUserDoclet.java index a09847073b2..7cb2041cfe6 100644 --- a/langtools/test/tools/javadoc/6964914/TestUserDoclet.java +++ b/langtools/test/tools/javadoc/6964914/TestUserDoclet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ */ import java.io.*; +import java.util.*; + import com.sun.javadoc.Doclet; import com.sun.javadoc.RootDoc; @@ -55,12 +57,20 @@ public class TestUserDoclet extends Doclet { // run javadoc in separate process to ensure doclet executed under // normal user conditions w.r.t. classloader String thisClassName = TestUserDoclet.class.getName(); - Process p = new ProcessBuilder() - .command(javadoc.getPath(), - "-J-Xpatch:" + System.getProperty("jdk.launcher.patch.0", ""), + List cmdArgs = new ArrayList<>(); + cmdArgs.add(javadoc.getPath()); + int i = 0; + String prop; + while ((prop = System.getProperty("jdk.launcher.patch." + (i++))) != null) { + cmdArgs.add("-J-Xpatch:" + prop); + } + cmdArgs.addAll(Arrays.asList( "-doclet", thisClassName, "-docletpath", testClasses.getPath(), - new File(testSrc, thisClassName + ".java").getPath()) + new File(testSrc, thisClassName + ".java").getPath() + )); + Process p = new ProcessBuilder() + .command(cmdArgs) .redirectErrorStream(true) .start(); From d6521300a0ff2896edd2e63113f9e740d855a71a Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 19 Apr 2016 14:16:39 +0200 Subject: [PATCH 029/222] 7020499: Project Coin: improvements to try-with-resources desugaring Avoid unnecessary check for resource nullness if the resource is known to be non-null; put resource closing code in a method that is shared by multiple try-with-resources. Reviewed-by: darcy, mcimadamore, vromero --- .../com/sun/tools/javac/comp/Lower.java | 105 +++++++++++- .../TryWithResources/TwrAvoidNullCheck.java | 125 ++++++++++++++ .../javac/TryWithResources/TwrClose.java | 140 ++++++++++++++++ .../TryWithResources/TwrShareCloseCode.java | 158 ++++++++++++++++++ .../referenceinfos/ResourceVariable.java | 14 +- .../tools/javac/flow/tests/TestCaseTry.java | 10 +- 6 files changed, 533 insertions(+), 19 deletions(-) create mode 100644 langtools/test/tools/javac/TryWithResources/TwrAvoidNullCheck.java create mode 100644 langtools/test/tools/javac/TryWithResources/TwrClose.java create mode 100644 langtools/test/tools/javac/TryWithResources/TwrShareCloseCode.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index 197cff5c3be..0bb1d96a7fb 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -86,6 +86,7 @@ public class Lower extends TreeTranslator { private final TypeEnvs typeEnvs; private final Name dollarAssertionsDisabled; private final Name classDollar; + private final Name dollarCloseResource; private final Types types; private final boolean debugLower; private final PkgInfo pkginfoOpt; @@ -109,6 +110,8 @@ public class Lower extends TreeTranslator { fromString(target.syntheticNameChar() + "assertionsDisabled"); classDollar = names. fromString("class" + target.syntheticNameChar()); + dollarCloseResource = names. + fromString(target.syntheticNameChar() + "closeResource"); types = Types.instance(context); Options options = Options.instance(context); @@ -1648,9 +1651,11 @@ public class Lower extends TreeTranslator { ListBuffer stats = new ListBuffer<>(); JCTree resource = resources.head; JCExpression expr = null; + boolean resourceNonNull; if (resource instanceof JCVariableDecl) { JCVariableDecl var = (JCVariableDecl) resource; expr = make.Ident(var.sym).setType(resource.type); + resourceNonNull = var.init != null && TreeInfo.skipParens(var.init).hasTag(NEWCLASS); stats.add(var); } else { Assert.check(resource instanceof JCExpression); @@ -1665,6 +1670,7 @@ public class Lower extends TreeTranslator { JCVariableDecl syntheticTwrVarDecl = make.VarDef(syntheticTwrVar, (JCExpression)resource); expr = (JCExpression)make.Ident(syntheticTwrVar); + resourceNonNull = TreeInfo.skipParens(resource).hasTag(NEWCLASS); stats.add(syntheticTwrVarDecl); } @@ -1694,7 +1700,7 @@ public class Lower extends TreeTranslator { int oldPos = make.pos; make.at(TreeInfo.endPos(block)); - JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr); + JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr, resourceNonNull); make.at(oldPos); JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block, finallyCanCompleteNormally, depth + 1), @@ -1706,7 +1712,96 @@ public class Lower extends TreeTranslator { return newBlock; } - private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource) { + /**If the estimated number of copies the close resource code in a single class is above this + * threshold, generate and use a method for the close resource code, leading to smaller code. + * As generating a method has overhead on its own, generating the method for cases below the + * threshold could lead to an increase in code size. + */ + public static final int USE_CLOSE_RESOURCE_METHOD_THRESHOLD = 4; + + private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource, + boolean resourceNonNull) { + MethodSymbol closeResource = (MethodSymbol)lookupSynthetic(dollarCloseResource, + currentClass.members()); + + if (closeResource == null && shouldUseCloseResourceMethod()) { + closeResource = new MethodSymbol( + PRIVATE | STATIC | SYNTHETIC, + dollarCloseResource, + new MethodType( + List.of(syms.throwableType, syms.autoCloseableType), + syms.voidType, + List.nil(), + syms.methodClass), + currentClass); + enterSynthetic(resource.pos(), closeResource, currentClass.members()); + + JCMethodDecl md = make.MethodDef(closeResource, null); + List params = md.getParameters(); + md.body = make.Block(0, List.of(makeTwrCloseStatement(params.get(0).sym, + make.Ident(params.get(1))))); + + JCClassDecl currentClassDecl = classDef(currentClass); + currentClassDecl.defs = currentClassDecl.defs.prepend(md); + } + + JCStatement closeStatement; + + if (closeResource != null) { + //$closeResource(#primaryException, #resource) + closeStatement = make.Exec(make.Apply(List.nil(), + make.Ident(closeResource), + List.of(make.Ident(primaryException), + resource) + ).setType(syms.voidType)); + } else { + closeStatement = makeTwrCloseStatement(primaryException, resource); + } + + JCStatement finallyStatement; + + if (resourceNonNull) { + finallyStatement = closeStatement; + } else { + // if (#resource != null) { $closeResource(...); } + finallyStatement = make.If(makeNonNullCheck(resource), + closeStatement, + null); + } + + return make.Block(0L, + List.of(finallyStatement)); + } + //where: + private boolean shouldUseCloseResourceMethod() { + class TryFinder extends TreeScanner { + int closeCount; + @Override + public void visitTry(JCTry tree) { + boolean empty = tree.body.stats.isEmpty(); + + for (JCTree r : tree.resources) { + closeCount += empty ? 1 : 2; + empty = false; //with multiple resources, only the innermost try can be empty. + } + super.visitTry(tree); + } + @Override + public void scan(JCTree tree) { + if (useCloseResourceMethod()) + return; + super.scan(tree); + } + boolean useCloseResourceMethod() { + return closeCount >= USE_CLOSE_RESOURCE_METHOD_THRESHOLD; + } + } + TryFinder tryFinder = new TryFinder(); + tryFinder.scan(classDef(currentClass)); + return tryFinder.useCloseResourceMethod(); + } + + private JCStatement makeTwrCloseStatement(Symbol primaryException, JCExpression resource) { // primaryException.addSuppressed(catchException); VarSymbol catchException = new VarSymbol(SYNTHETIC, make.paramName(2), @@ -1731,11 +1826,7 @@ public class Lower extends TreeTranslator { tryTree, makeResourceCloseInvocation(resource)); - // if (#resource != null) { if (primaryException ... } - return make.Block(0L, - List.of(make.If(makeNonNullCheck(resource), - closeIfStatement, - null))); + return closeIfStatement; } private JCStatement makeResourceCloseInvocation(JCExpression resource) { diff --git a/langtools/test/tools/javac/TryWithResources/TwrAvoidNullCheck.java b/langtools/test/tools/javac/TryWithResources/TwrAvoidNullCheck.java new file mode 100644 index 00000000000..f095b92b571 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrAvoidNullCheck.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 7020499 + * @summary Verify that try-with-resources desugaring is not generating unnecessary null checks + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask TwrAvoidNullCheck + * @run main TwrAvoidNullCheck + */ + +import java.io.IOException; +import java.util.Arrays; + +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; +import com.sun.tools.javac.comp.Lower; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Context.Factory; +import com.sun.tools.javac.util.List; + +import toolbox.ToolBox; + +public class TwrAvoidNullCheck { + public static void main(String... args) throws IOException { + new TwrAvoidNullCheck().run(); + } + void run() throws IOException { + run("new Test()", false); + run("null", true); + run("System.getProperty(\"test\") != null ? new Test() : null", true); + } + void run(String resourceSpecification, boolean expected) throws IOException { + String template = "public class Test implements AutoCloseable {\n" + + " void t() {\n" + + " try (Test resource = RESOURCE) { }\n" + + " }\n" + + " public void close() { }\n" + + "}\n"; + String code = template.replace("RESOURCE", resourceSpecification); + Context ctx = new Context(); + DumpLower.preRegister(ctx); + Iterable files = Arrays.asList(new ToolBox.JavaSource(code)); + JavacTask task = JavacTool.create().getTask(null, null, null, null, null, files, ctx); + task.call(); + + boolean hasNullCheck = ((DumpLower) DumpLower.instance(ctx)).hasNullCheck; + + if (hasNullCheck != expected) { + throw new IllegalStateException("expected: " + expected + + "; actual: " + hasNullCheck + + "; code: " + code); + } + } + + static class DumpLower extends Lower { + + public static void preRegister(Context ctx) { + ctx.put(lowerKey, new Factory() { + @Override + public Lower make(Context c) { + return new DumpLower(c); + } + }); + } + + public DumpLower(Context context) { + super(context); + } + + boolean hasNullCheck; + + @Override + public List translateTopLevelClass(Env env, JCTree cdef, TreeMaker make) { + List result = super.translateTopLevelClass(env, cdef, make); + + new TreeScanner() { + @Override + public void visitBinary(JCBinary tree) { + hasNullCheck |= tree.operator.getSimpleName().contentEquals("!=") && + "resource".equals(String.valueOf(TreeInfo.name(tree.lhs))) && + TreeInfo.isNull(tree.rhs); + super.visitBinary(tree); + } + }.scan(result); + + return result; + } + + } +} diff --git a/langtools/test/tools/javac/TryWithResources/TwrClose.java b/langtools/test/tools/javac/TryWithResources/TwrClose.java new file mode 100644 index 00000000000..504a05bd5b4 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrClose.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 7020499 + * @summary Verify that the close resource code works properly in all cases + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox TwrClose + * @run main TwrClose + */ + +import javax.tools.JavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +import com.sun.tools.javac.comp.Lower; + +import toolbox.JavacTask; +import toolbox.ToolBox; + +public class TwrClose { + + public static void main(String... args) throws Exception { + for (int i = 1; i < Lower.USE_CLOSE_RESOURCE_METHOD_THRESHOLD * 2; i++) { + new TwrClose().compile(i); + } + } + + ToolBox tb = new ToolBox(); + JavaFileManager fm = ToolProvider.getSystemJavaCompiler() + .getStandardFileManager(null, null, null); + + void compile(int trysCount) throws Exception { + StringBuilder testInvocations = new StringBuilder(); + StringBuilder testMethods = new StringBuilder(); + + for (int i = 0; i < trysCount; i++) { + testInvocations.append(TEST_INVOCATIONS_TEMPLATE.replace("#N", Integer.toString(i))); + testMethods.append(TEST_METHOD_TEMPLATE.replace("#N", Integer.toString(i))); + } + + String sourceCode = FILE_TEMPLATE.replace("#TEST_INVOCATIONS", testInvocations.toString()) + .replace("#TEST_METHODS", testMethods.toString()); + + System.err.println("analyzing:"); + System.err.println(sourceCode); + + try (ToolBox.MemoryFileManager mfm = new ToolBox.MemoryFileManager()) { + new JavacTask(tb).fileManager(mfm) + .sources(sourceCode) + .run() + .writeAll(); + ClassLoader cl = new ClassLoader(TwrClose.class.getClassLoader()) { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] data = mfm.getFileBytes(StandardLocation.CLASS_OUTPUT, name); + if (data != null) { + return defineClass(name, data, 0, data.length); + } + return super.findClass(name); + } + }; + + ((Runnable) cl.loadClass("Test").newInstance()).run(); + } + } + + final String TEST_INVOCATIONS_TEMPLATE = + " test#N(false, false, Arrays.asList(\"close\"));\n" + + " test#N(false, true, Arrays.asList(\"close\", \"close-exception\"));\n" + + " test#N(true, false, Arrays.asList(\"close\", \"inTwr\"));\n" + + " test#N(true, true, Arrays.asList(\"close\", \"inTwr\", \"close-exception\"));\n"; + + final String TEST_METHOD_TEMPLATE = + " private void test#N(boolean failInTwr, boolean failOnClose,\n" + + " List expectedMessages) {\n" + + " List messages = new ArrayList<>();\n" + + " try {\n" + + " try (CloseableImpl c = new CloseableImpl(messages, failOnClose)) {\n" + + " if (failInTwr)\n" + + " throw new IllegalStateException(\"inTwr\");\n" + + " }\n" + + " } catch (IllegalStateException ex) {\n" + + " messages.add(ex.getMessage());\n" + + " for (Throwable t : ex.getSuppressed()) {\n" + + " messages.add(t.getMessage());\n" + + " }\n" + + " }\n" + + " if (!expectedMessages.equals(messages))\n" + + " throw new AssertionError(\"Expected and actual messages differ; expectedMessages=\" +\n" + + " expectedMessages + \"; actual=\" + messages);\n" + + " }\n"; + + final String FILE_TEMPLATE = + "import java.util.*;\n" + + "public class Test implements Runnable {\n" + + " public void run() {\n" + + "#TEST_INVOCATIONS" + + " }\n" + + "#TEST_METHODS" + + " static class CloseableImpl implements AutoCloseable {\n" + + " private final List messages;\n" + + " private final boolean failOnClose;\n" + + " public CloseableImpl(List messages, boolean failOnClose) {\n" + + " this.messages = messages;\n" + + " this.failOnClose = failOnClose;\n" + + " }\n" + + " @Override\n" + + " public void close() {\n" + + " messages.add(\"close\");\n" + + " if (failOnClose)\n" + + " throw new IllegalStateException(\"close-exception\");\n" + + " }\n" + + " }\n" + + "}\n"; +} diff --git a/langtools/test/tools/javac/TryWithResources/TwrShareCloseCode.java b/langtools/test/tools/javac/TryWithResources/TwrShareCloseCode.java new file mode 100644 index 00000000000..0d6ff045ef7 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrShareCloseCode.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 7020499 + * @summary Verify that the code that closes the resources is shared by among try-with-resources + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox TwrShareCloseCode + * @run main TwrShareCloseCode + */ + +import java.io.IOException; +import java.util.Arrays; + +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; +import com.sun.tools.javac.comp.Lower; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Context.Factory; +import com.sun.tools.javac.util.List; + +import toolbox.ToolBox; + +public class TwrShareCloseCode { + public static void main(String... args) throws IOException { + new TwrShareCloseCode().run(); + } + + void run() throws IOException { + run("try (Test t1 = new Test()) { }", true); + run("try (Test t1 = new Test()) { }\n" + + "try (Test t2 = new Test()) { }", true); + run("try (Test t1 = new Test();\n" + + " Test t2 = new Test()) { }", true); + run("try (Test t1 = new Test()) { }\n" + + "try (Test t2 = new Test()) { }\n" + + "try (Test t3 = new Test()) { }", true); + run("try (Test t1 = new Test();\n" + + " Test t2 = new Test();\n" + + " Test t3 = new Test()) { }", false); + run("try (Test t1 = new Test()) { }\n" + + "try (Test t2 = new Test()) { }\n" + + "try (Test t3 = new Test()) { }\n" + + "try (Test t4 = new Test()) { }", false); + + run("try (Test t1 = new Test()) { i++; }", true); + run("try (Test t1 = new Test()) { i++; }\n" + + "try (Test t2 = new Test()) { i++; }", false); + + run("try (Test t1 = new Test(); Test t2 = new Test()) { i++; }", false); + + run("try (Test t1 = new Test()) { i++; }\n" + + "try (Test t2 = new Test()) { }", true); + + run("try (Test t1 = new Test()) { i++; }\n" + + "try (Test t2 = new Test()) { }\n" + + "try (Test t3 = new Test()) { }", false); + + run("try (Test t1 = new Test()) { i++; }\n" + + "try (Test t2 = new Test()) { i++; }\n" + + "try (Test t3 = new Test()) { }", false); + } + void run(String trySpec, boolean expected) throws IOException { + String template = "public class Test implements AutoCloseable {\n" + + " void t(int i) {\n" + + " TRY\n" + + " }\n" + + " public void close() { }\n" + + "}\n"; + String code = template.replace("TRY", trySpec); + Context ctx = new Context(); + DumpLower.preRegister(ctx); + Iterable files = Arrays.asList(new ToolBox.JavaSource(code)); + JavacTask task = JavacTool.create().getTask(null, null, null, null, null, files, ctx); + task.call(); + boolean actual = ((DumpLower) DumpLower.instance(ctx)).closeSeen; + + if (expected != actual) { + throw new IllegalStateException("expected: " + expected + "; actual: " + actual + "; code:\n" + code); + } + } + + static class DumpLower extends Lower { + + public static void preRegister(Context ctx) { + ctx.put(lowerKey, new Factory() { + @Override + public Lower make(Context c) { + return new DumpLower(c); + } + }); + } + + public DumpLower(Context context) { + super(context); + } + + boolean closeSeen; + + @Override + public List translateTopLevelClass(Env env, JCTree cdef, TreeMaker make) { + List result = super.translateTopLevelClass(env, cdef, make); + + new TreeScanner() { + @Override + public void visitMethodDef(JCMethodDecl tree) { + if (!tree.name.contentEquals("t")) + return; + + super.visitMethodDef(tree); + } + + @Override + public void visitApply(JCMethodInvocation tree) { + closeSeen |= TreeInfo.symbol(tree.meth).name.contentEquals("close"); + super.visitApply(tree); + } + }.scan(result); + + return result; + } + + } +} diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ResourceVariable.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ResourceVariable.java index 266a3e8a592..b65535badf5 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ResourceVariable.java +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ResourceVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,9 +36,9 @@ import static java.lang.System.lineSeparator; public class ResourceVariable { @TADescription(annotation = "TA", type = RESOURCE_VARIABLE, - lvarOffset = {10}, lvarLength = {118}, lvarIndex = {1}) + lvarOffset = {10}, lvarLength = {106}, lvarIndex = {1}) @TADescription(annotation = "TB", type = RESOURCE_VARIABLE, - lvarOffset = {22}, lvarLength = {35}, lvarIndex = {3}) + lvarOffset = {22}, lvarLength = {31}, lvarIndex = {3}) public String testResourceVariable() { return "public void f() throws IOException {" + lineSeparator() + @@ -49,7 +49,7 @@ public class ResourceVariable { } @TADescription(annotation = "RTAs", type = RESOURCE_VARIABLE, - lvarOffset = {10}, lvarLength = {30}, lvarIndex = {1}) + lvarOffset = {10}, lvarLength = {26}, lvarIndex = {1}) public String testRepeatedAnnotation1() { return "public void f() throws IOException {" + lineSeparator() + @@ -58,7 +58,7 @@ public class ResourceVariable { } @TADescription(annotation = "RTAs", type = RESOURCE_VARIABLE, - lvarOffset = {10}, lvarLength = {30}, lvarIndex = {1}) + lvarOffset = {10}, lvarLength = {26}, lvarIndex = {1}) public String testRepeatedAnnotation2() { return "public void f() throws IOException {" + lineSeparator() + @@ -67,9 +67,9 @@ public class ResourceVariable { } @TADescription(annotation = "TA", type = RESOURCE_VARIABLE, - lvarOffset = {10}, lvarLength = {118}, lvarIndex = {1}) + lvarOffset = {10}, lvarLength = {106}, lvarIndex = {1}) @TADescription(annotation = "TB", type = RESOURCE_VARIABLE, - lvarOffset = {22}, lvarLength = {35}, lvarIndex = {3}) + lvarOffset = {22}, lvarLength = {31}, lvarIndex = {3}) public String testSeveralVariablesInTryWithResources() { return "public void f() throws IOException {" + lineSeparator() + diff --git a/langtools/test/tools/javac/flow/tests/TestCaseTry.java b/langtools/test/tools/javac/flow/tests/TestCaseTry.java index b3a3762bd20..dbc1f2b9d74 100644 --- a/langtools/test/tools/javac/flow/tests/TestCaseTry.java +++ b/langtools/test/tools/javac/flow/tests/TestCaseTry.java @@ -52,9 +52,9 @@ public class TestCaseTry { o = ""; } - @AliveRange(varName="o", bytecodeStart=22, bytecodeLength=38) - @AliveRange(varName="o", bytecodeStart=103, bytecodeLength=3) - @AliveRange(varName="o", bytecodeStart=110, bytecodeLength=1) + @AliveRange(varName="o", bytecodeStart=22, bytecodeLength=13) + @AliveRange(varName="o", bytecodeStart=53, bytecodeLength=3) + @AliveRange(varName="o", bytecodeStart=60, bytecodeLength=1) void m3() { Object o; try (BufferedReader br = @@ -65,8 +65,8 @@ public class TestCaseTry { o = ""; } - @AliveRange(varName="o", bytecodeStart=12, bytecodeLength=96) - @AliveRange(varName="o", bytecodeStart=112, bytecodeLength=1) + @AliveRange(varName="o", bytecodeStart=12, bytecodeLength=46) + @AliveRange(varName="o", bytecodeStart=62, bytecodeLength=1) void m4() { String o; try (BufferedReader br = From 6921adecb8cb37b162181cd9665a34436c8b781c Mon Sep 17 00:00:00 2001 From: Robert Field Date: Wed, 20 Apr 2016 08:30:30 -0700 Subject: [PATCH 030/222] 8154445: JShell: Drop residual use of addReads from jshell Reviewed-by: alanb, ksrini --- .../share/classes/jdk/internal/jshell/remote/RemoteAgent.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java index 1a0cec3444f..f7d8e4a186d 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java @@ -113,7 +113,6 @@ class RemoteAgent { } Method doitMethod; try { - this.getClass().getModule().addReads(klass.getModule()); this.getClass().getModule().addExports(RemoteResolutionException.class.getPackage().getName(), klass.getModule()); doitMethod = klass.getDeclaredMethod(DOIT_METHOD_NAME, new Class[0]); doitMethod.setAccessible(true); @@ -184,7 +183,6 @@ class RemoteAgent { break; } try { - this.getClass().getModule().addReads(klass.getModule()); Field var = klass.getDeclaredField(varname); var.setAccessible(true); Object res = var.get(null); From ecfc09db1610dd4e7bb52e45d1fe82d6fa4e3768 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Wed, 20 Apr 2016 08:35:44 -0700 Subject: [PATCH 031/222] 8153551: jshell tool: no longer a mechanism to see current feedback modes Reviewed-by: jlahoda --- .../classes/jdk/internal/jshell/tool/Feedback.java | 11 ++++++++--- langtools/test/jdk/jshell/ToolFormatTest.java | 8 +++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java index 8ebf1216611..958116c6987 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java @@ -606,6 +606,7 @@ class Feedback { fluffmsg("jshell.msg.feedback.mode", mode.name); } else { fluffmsg("jshell.msg.see", "/help /set feedback"); + printFeedbackModes(); } return valid; } @@ -671,13 +672,17 @@ class Feedback { } else { errorat("jshell.err.feedback.ambiguous.mode", umode); } - fluffmsg("jshell.msg.feedback.mode.following"); - modeMap.keySet().stream() - .forEach(mk -> fluff(" %s", mk)); + printFeedbackModes(); return null; } } + void printFeedbackModes() { + fluffmsg("jshell.msg.feedback.mode.following"); + modeMap.keySet().stream() + .forEach(mk -> fluff(" %s", mk)); + } + // Test if the format string is correctly final String nextFormat() { String format = at.next(); diff --git a/langtools/test/jdk/jshell/ToolFormatTest.java b/langtools/test/jdk/jshell/ToolFormatTest.java index 6d61fba4671..f4758f8a876 100644 --- a/langtools/test/jdk/jshell/ToolFormatTest.java +++ b/langtools/test/jdk/jshell/ToolFormatTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8148316 8148317 8151755 8152246 + * @bug 8148316 8148317 8151755 8152246 8153551 * @summary Tests for output customization * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -155,6 +155,12 @@ public class ToolFormatTest extends ReplToolTesting { } } + public void testShowFeedbackModes() { + test( + (a) -> assertCommandOutputContains(a, "/set feedback", "normal") + ); + } + public void testSetNewModeQuiet() { try { test( From 25c9be01d56ca788a421ec2cd9bfa7cd2e5b31ce Mon Sep 17 00:00:00 2001 From: Oleg Barbashov Date: Wed, 20 Apr 2016 17:17:56 -0700 Subject: [PATCH 032/222] 8151777: Add "@index" tag to the sampleapi generator Reviewed-by: ksrini, bpatel --- .../sampleapi/lib/sampleapi/SampleApi.java | 5 ++- .../generator/DocCommentGenerator.java | 43 +++++++++++++++---- .../sampleapi/generator/PackageGenerator.java | 4 +- .../sampleapi/lib/sampleapi/SampleApi.java | 5 ++- .../generator/DocCommentGenerator.java | 43 +++++++++++++++---- .../sampleapi/generator/PackageGenerator.java | 4 +- 6 files changed, 80 insertions(+), 24 deletions(-) diff --git a/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/SampleApi.java b/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/SampleApi.java index 7b72cf0ba81..536787bcc26 100644 --- a/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/SampleApi.java +++ b/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/SampleApi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,5 +53,8 @@ public class SampleApi { public Fault(String msg) { super(msg); } + public Fault(String msg, Throwable th) { + super(msg, th); + } } } diff --git a/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java b/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java index 691cd90eafe..b3ca960fe4e 100644 --- a/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java +++ b/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * 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,6 +32,8 @@ import javax.lang.model.element.Modifier; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.List; +import java.util.HashMap; +import java.util.Map; class DocCommentGenerator { @@ -99,14 +101,25 @@ class DocCommentGenerator { LITERAL("@literal", "Use < and > brackets instead of < and > escapes."), CODE("@code", "(i) -> new Abc((i > 0) ? (i << 1) : 0)"), LINK("@link", ""), - VALUE("@value", ""); + VALUE("@value", ""), + INDEX("@index", "", true); String tagName; String tagValue; + boolean counted; + Map counters; InlineTag(String tagName, String tagValue) { + this(tagName, tagValue, false); + } + + InlineTag(String tagName, String tagValue, boolean counted) { this.tagName = tagName; this.tagValue = tagValue; + this.counted = counted; + if (counted) { + counters = new HashMap<>(); + } } public String toString() { @@ -114,9 +127,14 @@ class DocCommentGenerator { } public String value(String value) { + String name = ((tagValue.length() != 0) ? " " + tagValue : "") + + ((value.length() != 0) ? " " + value : ""); + if (counted && !counters.containsKey(name)) { + counters.put(name, 0); + } return "{" + tagName - + ((tagValue.length() != 0) ? " " + tagValue : "") - + ((value.length() != 0) ? " " + value : "") + + name + + (counted ? "_" + counters.put(name, counters.get(name) + 1) : "") + "}"; } } @@ -179,7 +197,8 @@ class DocCommentGenerator { // public String getPackageComment() { - return Text.LOREMIPSUM + return InlineTag.INDEX.value("PackageCommentLabel") + " " + + Text.LOREMIPSUM + "\n

    " + Text.LIEUROPANLINGUES + "\n" + Text.CODE + "\n" + LinkTag.nextLink() @@ -192,7 +211,9 @@ class DocCommentGenerator { static int serialValIdx = 0; public String getBaseComment(JCClassDecl baseDecl, boolean toplevel) { - String buildComment = Text.LIEUROPANLINGUES + "\n"; + String buildComment = InlineTag.INDEX.value("BaseCommentLabel") + " "; + + buildComment += Text.LIEUROPANLINGUES + "\n"; buildComment += "

    It is possible to see inlined code:\n" + InlineTag.CODE @@ -237,8 +258,9 @@ class DocCommentGenerator { } public String getConstComment() { - String buildComment = Text.NOWISTHETIME + " " + Text.BROWNFOX + "\n"; + String buildComment = InlineTag.INDEX.value("ConstCommentLabel") + " "; + buildComment += Text.NOWISTHETIME + " " + Text.BROWNFOX + "\n"; buildComment += LinkTag.nextLink() + "\n"; buildComment += LinkTag.nextSee() + "\n"; buildComment += Tag.SINCE + "\n"; @@ -249,8 +271,9 @@ class DocCommentGenerator { public String getFieldComment(JCClassDecl baseDecl, JCVariableDecl varDecl, boolean isFxStyle) { - String buildComment = Text.BROWNFOX + "

    " + Text.NOWISTHETIME + "\n"; + String buildComment = InlineTag.INDEX.value("FieldCommentLabel") + " "; + buildComment += Text.BROWNFOX + "

    " + Text.NOWISTHETIME + "\n"; Set mods = varDecl.getModifiers().getFlags(); String varName = varDecl.getName().toString(); @@ -299,7 +322,9 @@ class DocCommentGenerator { public String getMethodComment(JCClassDecl baseDecl, JCMethodDecl methodDecl, boolean isFxStyle) { - String buildComment = Text.BROWNFOX + "\n

    " + Text.THISPANGRAM + "\n"; + String buildComment = InlineTag.INDEX.value("MethodCommentLabel") + " "; + + buildComment += Text.BROWNFOX + "\n

    " + Text.THISPANGRAM + "\n"; buildComment += "

    " + LinkTag.nextLink() + "\n"; diff --git a/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/generator/PackageGenerator.java b/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/generator/PackageGenerator.java index 05e5524fc0d..8e7ed7c1d4c 100644 --- a/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/generator/PackageGenerator.java +++ b/langtools/test/jdk/javadoc/tool/sampleapi/lib/sampleapi/generator/PackageGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,7 +125,7 @@ public class PackageGenerator { processTopLevel((Element)node); } } catch (ParserConfigurationException | SAXException | IOException e) { - throw new Fault("Error parsing dataset " + dsName); + throw new Fault("Error parsing dataset " + dsName, e); } fx = false; diff --git a/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApi.java b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApi.java index 7b72cf0ba81..536787bcc26 100644 --- a/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApi.java +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,5 +53,8 @@ public class SampleApi { public Fault(String msg) { super(msg); } + public Fault(String msg, Throwable th) { + super(msg, th); + } } } diff --git a/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java index 691cd90eafe..b3ca960fe4e 100644 --- a/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * 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,6 +32,8 @@ import javax.lang.model.element.Modifier; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.List; +import java.util.HashMap; +import java.util.Map; class DocCommentGenerator { @@ -99,14 +101,25 @@ class DocCommentGenerator { LITERAL("@literal", "Use < and > brackets instead of < and > escapes."), CODE("@code", "(i) -> new Abc((i > 0) ? (i << 1) : 0)"), LINK("@link", ""), - VALUE("@value", ""); + VALUE("@value", ""), + INDEX("@index", "", true); String tagName; String tagValue; + boolean counted; + Map counters; InlineTag(String tagName, String tagValue) { + this(tagName, tagValue, false); + } + + InlineTag(String tagName, String tagValue, boolean counted) { this.tagName = tagName; this.tagValue = tagValue; + this.counted = counted; + if (counted) { + counters = new HashMap<>(); + } } public String toString() { @@ -114,9 +127,14 @@ class DocCommentGenerator { } public String value(String value) { + String name = ((tagValue.length() != 0) ? " " + tagValue : "") + + ((value.length() != 0) ? " " + value : ""); + if (counted && !counters.containsKey(name)) { + counters.put(name, 0); + } return "{" + tagName - + ((tagValue.length() != 0) ? " " + tagValue : "") - + ((value.length() != 0) ? " " + value : "") + + name + + (counted ? "_" + counters.put(name, counters.get(name) + 1) : "") + "}"; } } @@ -179,7 +197,8 @@ class DocCommentGenerator { // public String getPackageComment() { - return Text.LOREMIPSUM + return InlineTag.INDEX.value("PackageCommentLabel") + " " + + Text.LOREMIPSUM + "\n

    " + Text.LIEUROPANLINGUES + "\n" + Text.CODE + "\n" + LinkTag.nextLink() @@ -192,7 +211,9 @@ class DocCommentGenerator { static int serialValIdx = 0; public String getBaseComment(JCClassDecl baseDecl, boolean toplevel) { - String buildComment = Text.LIEUROPANLINGUES + "\n"; + String buildComment = InlineTag.INDEX.value("BaseCommentLabel") + " "; + + buildComment += Text.LIEUROPANLINGUES + "\n"; buildComment += "

    It is possible to see inlined code:\n" + InlineTag.CODE @@ -237,8 +258,9 @@ class DocCommentGenerator { } public String getConstComment() { - String buildComment = Text.NOWISTHETIME + " " + Text.BROWNFOX + "\n"; + String buildComment = InlineTag.INDEX.value("ConstCommentLabel") + " "; + buildComment += Text.NOWISTHETIME + " " + Text.BROWNFOX + "\n"; buildComment += LinkTag.nextLink() + "\n"; buildComment += LinkTag.nextSee() + "\n"; buildComment += Tag.SINCE + "\n"; @@ -249,8 +271,9 @@ class DocCommentGenerator { public String getFieldComment(JCClassDecl baseDecl, JCVariableDecl varDecl, boolean isFxStyle) { - String buildComment = Text.BROWNFOX + "

    " + Text.NOWISTHETIME + "\n"; + String buildComment = InlineTag.INDEX.value("FieldCommentLabel") + " "; + buildComment += Text.BROWNFOX + "

    " + Text.NOWISTHETIME + "\n"; Set mods = varDecl.getModifiers().getFlags(); String varName = varDecl.getName().toString(); @@ -299,7 +322,9 @@ class DocCommentGenerator { public String getMethodComment(JCClassDecl baseDecl, JCMethodDecl methodDecl, boolean isFxStyle) { - String buildComment = Text.BROWNFOX + "\n

    " + Text.THISPANGRAM + "\n"; + String buildComment = InlineTag.INDEX.value("MethodCommentLabel") + " "; + + buildComment += Text.BROWNFOX + "\n

    " + Text.THISPANGRAM + "\n"; buildComment += "

    " + LinkTag.nextLink() + "\n"; diff --git a/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/PackageGenerator.java b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/PackageGenerator.java index 05e5524fc0d..8e7ed7c1d4c 100644 --- a/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/PackageGenerator.java +++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/PackageGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,7 +125,7 @@ public class PackageGenerator { processTopLevel((Element)node); } } catch (ParserConfigurationException | SAXException | IOException e) { - throw new Fault("Error parsing dataset " + dsName); + throw new Fault("Error parsing dataset " + dsName, e); } fx = false; From c413f5eb4419bdf83ddcfc672a4230e42a0e36fa Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 21 Apr 2016 12:57:16 -0700 Subject: [PATCH 033/222] Added tag jdk-9+115 for changeset c36230ee15d9 --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index 8032358a539..e8881f37c97 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -357,3 +357,4 @@ f5991c73ed73b9a355a090b65c8d7fb9a1901f89 jdk-9+109 3d4117c36559b344a73f786d39cc7626b4d8e2c0 jdk-9+112 4e87682893e662421af10a62d29ae822ce0fea04 jdk-9+113 cba09a2e6ae969b029783eb59bb01017b78f8eef jdk-9+114 +31c8b18fdc5b94a2ddd5ea0694f350a2c907e9f7 jdk-9+115 From e85033c628f607fee4e9365938534ab56cedbfd3 Mon Sep 17 00:00:00 2001 From: Andreas Lundblad Date: Tue, 22 Mar 2016 13:14:12 +0100 Subject: [PATCH 034/222] 8048146: sjavac uses unexpected exit code of -1 Changed exit codes for sjavac Reviewed-by: jlahoda --- .../sun/tools/sjavac/CompileJavaPackages.java | 7 ++--- .../sun/tools/sjavac/client/ClientMain.java | 8 +++-- .../sun/tools/sjavac/client/SjavacClient.java | 25 +++++++++------- .../tools/sjavac/comp/CompilationService.java | 21 +++++++++----- .../sun/tools/sjavac/comp/PooledSjavac.java | 3 +- .../com/sun/tools/sjavac/comp/SjavacImpl.java | 29 ++++++++++--------- .../sjavac/server/CompilationSubResult.java | 16 +++++----- .../tools/sjavac/server/IdleResetSjavac.java | 6 ++-- .../tools/sjavac/server/RequestHandler.java | 5 ++-- .../sun/tools/sjavac/server/ServerMain.java | 6 ++-- .../com/sun/tools/sjavac/server/Sjavac.java | 8 ++--- .../sun/tools/sjavac/server/SjavacServer.java | 6 ++-- langtools/test/tools/sjavac/HiddenFiles.java | 3 +- langtools/test/tools/sjavac/IdleShutdown.java | 6 ++-- .../tools/sjavac/IncludeExcludePatterns.java | 3 +- .../test/tools/sjavac/PooledExecution.java | 8 ++--- 16 files changed, 84 insertions(+), 76 deletions(-) diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java index f6ac5d2ad44..18a079dad9d 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java @@ -26,8 +26,6 @@ package com.sun.tools.sjavac; import java.io.File; -import java.io.IOException; -import java.io.Writer; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -42,9 +40,8 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.regex.Pattern; -import java.util.stream.Stream; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.comp.CompilationService; import com.sun.tools.sjavac.options.Options; import com.sun.tools.sjavac.pubapi.PubApi; @@ -283,7 +280,7 @@ public class CompileJavaPackages implements Transformer { } // Check the return values. - if (subResult.returnCode != 0) { + if (subResult.result != Result.OK) { rc = false; } } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java index 54c1e51952f..5ba63fed8d5 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java @@ -28,6 +28,8 @@ package com.sun.tools.sjavac.client; import java.io.OutputStreamWriter; import java.io.Writer; +import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.AutoFlushWriter; import com.sun.tools.sjavac.Log; import com.sun.tools.sjavac.Util; @@ -58,7 +60,7 @@ public class ClientMain { options = Options.parseArgs(args); } catch (IllegalArgumentException e) { Log.error(e.getMessage()); - return -1; + return Result.CMDERR.exitCode; } Log.setLogLevel(options.getLogLevel()); @@ -73,13 +75,13 @@ public class ClientMain { Sjavac sjavac = useServer ? new SjavacClient(options) : new SjavacImpl(); // Perform compilation - int rc = sjavac.compile(args); + Result result = sjavac.compile(args); // If sjavac is running in the foreground we should shut it down at this point if (!useServer) { sjavac.shutdown(); } - return rc; + return result.exitCode; } } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java index 37fb47890c2..570530d7028 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java @@ -26,23 +26,20 @@ package com.sun.tools.sjavac.client; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; -import java.io.PrintStream; import java.io.PrintWriter; import java.io.Reader; -import java.io.Writer; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Scanner; -import java.util.stream.Stream; +import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.Log; import com.sun.tools.sjavac.Util; import com.sun.tools.sjavac.options.OptionHelper; @@ -116,8 +113,8 @@ public class SjavacClient implements Sjavac { } @Override - public int compile(String[] args) { - int result = -1; + public Result compile(String[] args) { + Result result = null; try (Socket socket = tryConnect()) { PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); @@ -150,22 +147,28 @@ public class SjavacClient implements Sjavac { } if (type.equals(SjavacServer.LINE_TYPE_RC)) { - result = Integer.parseInt(content); + result = Main.Result.valueOf(content); } } } catch (PortFileInaccessibleException e) { Log.error("Port file inaccessible."); - result = CompilationSubResult.ERROR_FATAL; + result = Result.ERROR; } catch (IOException ioe) { Log.error("IOException caught during compilation: " + ioe.getMessage()); Log.debug(ioe); - result = CompilationSubResult.ERROR_FATAL; + result = Result.ERROR; } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // Restore interrupt Log.error("Compilation interrupted."); Log.debug(ie); - result = CompilationSubResult.ERROR_FATAL; + result = Result.ERROR; } + + if (result == null) { + // No LINE_TYPE_RC was found. + result = Result.ERROR; + } + return result; } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/CompilationService.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/CompilationService.java index 0eb4f7e2358..bf55947827c 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/CompilationService.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/CompilationService.java @@ -42,6 +42,8 @@ import javax.tools.ToolProvider; import com.sun.tools.javac.api.JavacTaskImpl; import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Dependencies; import com.sun.tools.javac.util.ListBuffer; @@ -80,7 +82,7 @@ public class CompilationService { Dependencies.GraphDependencies.preRegister(context); // Now setup the actual compilation - CompilationSubResult compilationResult = new CompilationSubResult(0); + CompilationSubResult compilationResult = new CompilationSubResult(Result.OK); // First deal with explicit source files on cmdline and in at file ListBuffer explicitJFOs = new ListBuffer<>(); @@ -97,7 +99,7 @@ public class CompilationService { // Create a log to capture compiler output StringWriter stderrLog = new StringWriter(); - com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK; + Result result; PublicApiCollector pubApiCollector = new PublicApiCollector(context, explicitJFOs); PathAndPackageVerifier papVerifier = new PathAndPackageVerifier(); NewDependencyCollector depsCollector = new NewDependencyCollector(context, explicitJFOs); @@ -120,20 +122,23 @@ public class CompilationService { task.addTaskListener(pubApiCollector); task.addTaskListener(papVerifier); logJavacInvocation(args); - rc = task.doCall(); - Log.debug("javac returned with code " + rc); + result = task.doCall(); + Log.debug("javac result: " + result); sfm.flush(); + } else { + result = Result.ERROR; } } catch (Exception e) { Log.error(Util.getStackTrace(e)); stderrLog.append(Util.getStackTrace(e)); - rc = com.sun.tools.javac.main.Main.Result.ERROR; + result = Result.ERROR; } compilationResult.packageArtifacts = sfm.getPackageArtifacts(); - if (papVerifier.errorsDiscovered()) - rc = com.sun.tools.javac.main.Main.Result.ERROR; + if (papVerifier.errorsDiscovered()) { + result = Result.ERROR; + } compilationResult.packageDependencies = depsCollector.getDependencies(false); compilationResult.packageCpDependencies = depsCollector.getDependencies(true); @@ -141,7 +146,7 @@ public class CompilationService { compilationResult.packagePubapis = pubApiCollector.getPubApis(true); compilationResult.dependencyPubapis = pubApiCollector.getPubApis(false); compilationResult.stderr = stderrLog.toString(); - compilationResult.returnCode = rc.exitCode; + compilationResult.result = result; return compilationResult; } catch (IOException e) { diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java index 82be0ae3b16..f84d52d5296 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java @@ -25,6 +25,7 @@ package com.sun.tools.sjavac.comp; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.Log; import com.sun.tools.sjavac.server.Sjavac; @@ -54,7 +55,7 @@ public class PooledSjavac implements Sjavac { } @Override - public int compile(String[] args) { + public Result compile(String[] args) { Log log = Log.get(); try { return pool.submit(() -> { diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java index 4c39a70f779..3553fcf9075 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java @@ -41,6 +41,7 @@ import java.util.stream.Stream; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.javac.util.Context; import com.sun.tools.sjavac.JavacState; import com.sun.tools.sjavac.Log; @@ -69,36 +70,36 @@ import javax.tools.JavaFileManager; public class SjavacImpl implements Sjavac { @Override - public int compile(String[] args) { + public Result compile(String[] args) { Options options; try { options = Options.parseArgs(args); } catch (IllegalArgumentException e) { Log.error(e.getMessage()); - return RC_FATAL; + return Result.CMDERR; } if (!validateOptions(options)) - return RC_FATAL; + return Result.CMDERR; if (srcDstOverlap(options.getSources(), options.getDestDir())) { - return RC_FATAL; + return Result.CMDERR; } if (!createIfMissing(options.getDestDir())) - return RC_FATAL; + return Result.ERROR; Path stateDir = options.getStateDir(); if (stateDir != null && !createIfMissing(options.getStateDir())) - return RC_FATAL; + return Result.ERROR; Path gensrc = options.getGenSrcDir(); if (gensrc != null && !createIfMissing(gensrc)) - return RC_FATAL; + return Result.ERROR; Path hdrdir = options.getHeaderDir(); if (hdrdir != null && !createIfMissing(hdrdir)) - return RC_FATAL; + return Result.ERROR; if (stateDir == null) { // Prepare context. Direct logging to our byte array stream. @@ -113,7 +114,7 @@ public class SjavacImpl implements Sjavac { .filter(arg -> !arg.startsWith(Option.SERVER.arg)) .toArray(String[]::new); // Compile - Main.Result result = new Main("javac", printWriter).compile(passThroughArgs, context); + Result result = new Main("javac", printWriter).compile(passThroughArgs, context); // Process compiler output (which is always errors) printWriter.flush(); @@ -128,7 +129,7 @@ public class SjavacImpl implements Sjavac { throw new UncheckedIOException(es); } } - return result.exitCode; + return result; } else { // Load the prev build state database. @@ -166,7 +167,7 @@ public class SjavacImpl implements Sjavac { if (sources.isEmpty()) { Log.error("Found nothing to compile!"); - return RC_FATAL; + return Result.ERROR; } @@ -292,15 +293,15 @@ public class SjavacImpl implements Sjavac { javac_state.removeSuperfluousArtifacts(recently_compiled); } - return rc[0] ? RC_OK : RC_FATAL; + return rc[0] ? Result.OK : Result.ERROR; } catch (ProblemException e) { // For instance make file list mismatch. Log.error(e.getMessage()); Log.debug(e); - return RC_FATAL; + return Result.ERROR; } catch (Exception e) { Log.error(e); - return RC_FATAL; + return Result.ERROR; } } } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/CompilationSubResult.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/CompilationSubResult.java index 1b96379b79d..5a60aa2bef7 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/CompilationSubResult.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/CompilationSubResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.pubapi.PubApi; /** @@ -44,10 +45,7 @@ public class CompilationSubResult implements Serializable { static final long serialVersionUID = 46739181113L; - // Return code constants - public final static int ERROR_FATAL = -1; - - public int returnCode; + public Result result; public Map> packageArtifacts = new HashMap<>(); public Map>> packageDependencies = new HashMap<>(); public Map>> packageCpDependencies = new HashMap<>(); @@ -56,11 +54,11 @@ public class CompilationSubResult implements Serializable { public String stdout = ""; public String stderr = ""; - public CompilationSubResult(int returnCode) { - this.returnCode = returnCode; + public CompilationSubResult(Result result) { + this.result = result; } - public void setReturnCode(int returnCode) { - this.returnCode = returnCode; + public void setResult(Result result) { + this.result = result; } } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java index 8b7d17b0c0c..724c5062d5d 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java @@ -25,11 +25,9 @@ package com.sun.tools.sjavac.server; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.Log; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; import java.util.Timer; import java.util.TimerTask; @@ -66,7 +64,7 @@ public class IdleResetSjavac implements Sjavac { } @Override - public int compile(String[] args) { + public Result compile(String[] args) { startCall(); try { return delegate.compile(args); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java index 62ba3b995a9..e26a5c77766 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java @@ -25,6 +25,7 @@ package com.sun.tools.sjavac.server; +import com.sun.tools.javac.main.Main; import com.sun.tools.sjavac.Log; import com.sun.tools.sjavac.Util; @@ -100,10 +101,10 @@ public class RequestHandler extends Thread { checkInternalErrorLog(); // Perform compilation - int rc = sjavac.compile(args); + Main.Result rc = sjavac.compile(args); // Send return code back to client - out.println(LINE_TYPE_RC + ":" + rc); + out.println(LINE_TYPE_RC + ":" + rc.name()); // Check for internal errors again. checkInternalErrorLog(); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java index 6690c3ece70..39c22966e22 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java @@ -32,6 +32,8 @@ import java.io.IOException; import java.io.PrintStream; import java.lang.Thread.UncaughtExceptionHandler; +import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.Log; import com.sun.tools.sjavac.Log.Level; import com.sun.tools.sjavac.server.log.LazyInitFileLog; @@ -75,7 +77,7 @@ public class ServerMain { // Any options other than --startserver? if (args.length > 1) { Log.error("When spawning a background server, only a single --startserver argument is allowed."); - return 1; + return Result.CMDERR.exitCode; } int exitCode; @@ -84,7 +86,7 @@ public class ServerMain { exitCode = server.startServer(); } catch (IOException | InterruptedException ex) { ex.printStackTrace(); - exitCode = -1; + exitCode = Result.ERROR.exitCode; } return exitCode; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java index 91063c5a809..dd3c43db74d 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java @@ -25,6 +25,8 @@ package com.sun.tools.sjavac.server; +import com.sun.tools.javac.main.Main.Result; + import java.io.Writer; @@ -38,10 +40,6 @@ import java.io.Writer; * deletion without notice. */ public interface Sjavac { - - final static int RC_FATAL = -1; - final static int RC_OK = 0; - - int compile(String[] args); + Result compile(String[] args); void shutdown(); } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java index 16450295afe..d7dcc203ade 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java @@ -40,6 +40,8 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; +import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.Log; import com.sun.tools.sjavac.Util; import com.sun.tools.sjavac.client.PortFileInaccessibleException; @@ -167,7 +169,7 @@ public class SjavacServer implements Terminable { if (portFile.containsPortInfo()) { Log.debug("Javac server not started because portfile exists!"); portFile.unlock(); - return -1; + return Result.ERROR.exitCode; } // .-----------. .--------. .------. @@ -221,7 +223,7 @@ public class SjavacServer implements Terminable { // Shut down sjavac.shutdown(); - return 0; + return Result.OK.exitCode; } @Override diff --git a/langtools/test/tools/sjavac/HiddenFiles.java b/langtools/test/tools/sjavac/HiddenFiles.java index f6a7c7ba91d..237146af29b 100644 --- a/langtools/test/tools/sjavac/HiddenFiles.java +++ b/langtools/test/tools/sjavac/HiddenFiles.java @@ -36,6 +36,7 @@ * @run main Wrapper HiddenFiles */ +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.javac.util.Assert; import com.sun.tools.sjavac.server.Sjavac; @@ -62,6 +63,6 @@ public class HiddenFiles extends SjavacBase { "-d", BIN.toString(), "--state-dir=" + STATE_DIR); - Assert.check(rc == Sjavac.RC_FATAL, "Compilation succeeded unexpectedly."); + Assert.check(rc == Result.ERROR.exitCode, "Compilation succeeded unexpectedly."); } } diff --git a/langtools/test/tools/sjavac/IdleShutdown.java b/langtools/test/tools/sjavac/IdleShutdown.java index 7178d6c89e5..334f03149c2 100644 --- a/langtools/test/tools/sjavac/IdleShutdown.java +++ b/langtools/test/tools/sjavac/IdleShutdown.java @@ -29,9 +29,9 @@ * @build Wrapper * @run main Wrapper IdleShutdown */ -import java.io.Writer; import java.util.concurrent.atomic.AtomicLong; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.server.IdleResetSjavac; import com.sun.tools.sjavac.server.Sjavac; import com.sun.tools.sjavac.server.Terminable; @@ -103,13 +103,13 @@ public class IdleShutdown { public void shutdown() { } @Override - public int compile(String[] args) { + public Result compile(String[] args) { // Attempt to trigger idle timeout during a call by sleeping try { Thread.sleep(TIMEOUT_MS + 1000); } catch (InterruptedException e) { } - return 0; + return Result.OK; } } } diff --git a/langtools/test/tools/sjavac/IncludeExcludePatterns.java b/langtools/test/tools/sjavac/IncludeExcludePatterns.java index 41b02a3ddbe..6e38aadc218 100644 --- a/langtools/test/tools/sjavac/IncludeExcludePatterns.java +++ b/langtools/test/tools/sjavac/IncludeExcludePatterns.java @@ -33,6 +33,7 @@ * @run main Wrapper IncludeExcludePatterns */ +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.javac.util.Assert; import com.sun.tools.sjavac.server.Sjavac; @@ -131,7 +132,7 @@ public class IncludeExcludePatterns extends SjavacBase { int rc = compile((Object[]) args.split(" ")); // Compilation should always pass in these tests - Assert.check(rc == Sjavac.RC_OK, "Compilation failed unexpectedly."); + Assert.check(rc == Result.OK.exitCode, "Compilation failed unexpectedly."); // The resulting .class files should correspond to the visible source files Set result = allFilesInDir(BIN); diff --git a/langtools/test/tools/sjavac/PooledExecution.java b/langtools/test/tools/sjavac/PooledExecution.java index ccd4265fee2..bfa24b4fdcd 100644 --- a/langtools/test/tools/sjavac/PooledExecution.java +++ b/langtools/test/tools/sjavac/PooledExecution.java @@ -30,12 +30,10 @@ * @build Wrapper * @run main Wrapper PooledExecution */ -import java.io.PrintWriter; -import java.io.Writer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; -import com.sun.tools.sjavac.Log; +import com.sun.tools.javac.main.Main.Result; import com.sun.tools.sjavac.comp.PooledSjavac; import com.sun.tools.sjavac.server.Sjavac; @@ -111,7 +109,7 @@ public class PooledExecution { AtomicInteger activeRequests = new AtomicInteger(0); @Override - public int compile(String[] args) { + public Result compile(String[] args) { leftToStart.countDown(); int numActiveRequests = activeRequests.incrementAndGet(); System.out.printf("Left to start: %2d / Currently active: %2d%n", @@ -125,7 +123,7 @@ public class PooledExecution { } activeRequests.decrementAndGet(); System.out.println("Task completed"); - return 0; + return Result.OK; } @Override From 8543426a278f7d168c1985827a5bb49597080ab5 Mon Sep 17 00:00:00 2001 From: Ambarish Rapte Date: Wed, 30 Mar 2016 15:26:10 +0530 Subject: [PATCH 035/222] 8033936: java.awt.List events are not sent properly to handleEvent or ItemListener Reviewed-by: serb, psadhukhan --- .../windows/native/libawt/windows/awt_List.h | 1 + .../awt/List/ItemEventTest/ItemEventTest.java | 143 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 jdk/test/java/awt/List/ItemEventTest/ItemEventTest.java diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.h b/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.h index 73effc3a56e..3450089b509 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.h +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.h @@ -56,6 +56,7 @@ public: } INLINE void Deselect(int pos) { if (isMultiSelect) { + SendListMessage(LB_SETCARETINDEX, pos, FALSE); SendListMessage(LB_SETSEL, FALSE, pos); } else { diff --git a/jdk/test/java/awt/List/ItemEventTest/ItemEventTest.java b/jdk/test/java/awt/List/ItemEventTest/ItemEventTest.java new file mode 100644 index 00000000000..c239b01360c --- /dev/null +++ b/jdk/test/java/awt/List/ItemEventTest/ItemEventTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8033936 + * @summary Verify that correct ItemEvent is received while selection & + * deselection of multi select List items. + */ + +import java.awt.AWTException; +import java.awt.Event; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.event.InputEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +public class ItemEventTest extends Frame +{ + List list; + final String expectedSelectionOrder; + StringBuilder actualSelectionOrder; + Robot robot; + + public ItemEventTest() + { + try { + robot = new Robot(); + } catch(AWTException e) { + throw new RuntimeException(e.getMessage()); + } + expectedSelectionOrder = "01230123"; + + list = new List(4, true); + list.add("0"); + list.add("1"); + list.add("2"); + list.add("3"); + + add(list); + setSize(400,400); + setLayout(new FlowLayout()); + pack(); + setVisible(true); + robot.waitForIdle(); + } + + @Override + public boolean handleEvent(Event e) { + if (e.target instanceof List) { + if (e.id == Event.LIST_DESELECT || e.id == Event.LIST_SELECT) { + actualSelectionOrder.append(e.arg); + } + } + return true; + } + + void testHandleEvent() { + // When no ItemListener is added to List, parent's handleEvent is + // called with ItemEvent. + performTest(); + } + + void testItemListener() { + list.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent ie) { + actualSelectionOrder.append(ie.getItem()); + } + }); + performTest(); + } + + void performTest() { + actualSelectionOrder = new StringBuilder(); + Point loc = list.getLocationOnScreen(); + Rectangle rect = list.getBounds(); + int dY = rect.height / list.getItemCount(); + loc = new Point(loc.x + 10, loc.y + 5); + + String osName = System.getProperty("os.name"); + boolean isMac = osName.contains("Mac") || osName.contains("mac"); + if(isMac) { + robot.keyPress(KeyEvent.VK_META); + } + + // First loop to select & Second loop to deselect the list items. + for (int j = 0; j < 2; ++j) { + for (int i = 0; i < list.getItemCount(); ++i) { + robot.mouseMove(loc.x, loc.y + i * dY); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.delay(100); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + } + } + + if(isMac) { + robot.keyRelease(KeyEvent.VK_META); + } + + if (!expectedSelectionOrder.equals(actualSelectionOrder.toString())) { + dispose(); + throw new RuntimeException("ItemEvent for selection & deselection" + + " of multi select List's item is not correct" + + " Expected : " + expectedSelectionOrder + + " Actual : " + actualSelectionOrder); + } + } + + public static void main(String args[]) { + ItemEventTest test = new ItemEventTest(); + test.testHandleEvent(); + test.testItemListener(); + test.dispose(); + } +} From 61f991148093946b63a335a44cb08153f3b5ecc5 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 30 Mar 2016 16:00:43 +0530 Subject: [PATCH 036/222] 8061258: [macosx] PrinterJob's native Print Dialog does not reflect specified Copies or Page Ranges Reviewed-by: prr, jdv --- .../native/libawt_lwawt/awt/CPrinterJob.m | 50 +++--- .../awt/print/PrinterJob/DlgAttrsBug.java | 152 ++++++++++++++++++ 2 files changed, 179 insertions(+), 23 deletions(-) create mode 100644 jdk/test/java/awt/print/PrinterJob/DlgAttrsBug.java diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m index 165e7029497..b1428528730 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m @@ -368,6 +368,8 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj static JNF_MEMBER_CACHE(jm_isCollated, sjc_CPrinterJob, "isCollated", "()Z"); static JNF_MEMBER_CACHE(jm_getFromPage, sjc_CPrinterJob, "getFromPageAttrib", "()I"); static JNF_MEMBER_CACHE(jm_getToPage, sjc_CPrinterJob, "getToPageAttrib", "()I"); + static JNF_MEMBER_CACHE(jm_getMinPage, sjc_CPrinterJob, "getMinPageAttrib", "()I"); + static JNF_MEMBER_CACHE(jm_getMaxPage, sjc_CPrinterJob, "getMaxPageAttrib", "()I"); static JNF_MEMBER_CACHE(jm_getSelectAttrib, sjc_CPrinterJob, "getSelectAttrib", "()I"); static JNF_MEMBER_CACHE(jm_getNumberOfPages, jc_Pageable, "getNumberOfPages", "()I"); static JNF_MEMBER_CACHE(jm_getPageFormat, sjc_CPrinterJob, "getPageFormatFromAttributes", "()Ljava/awt/print/PageFormat;"); @@ -379,31 +381,33 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj jboolean collated = JNFCallBooleanMethod(env, srcPrinterJob, jm_isCollated); // AWT_THREADING Safe (known object) [printingDictionary setObject:[NSNumber numberWithBool:collated ? YES : NO] forKey:NSPrintMustCollate]; - jint jNumPages = JNFCallIntMethod(env, srcPageable, jm_getNumberOfPages); // AWT_THREADING Safe (!appKit) - if (jNumPages != java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES) - { - jint selectID = JNFCallIntMethod(env, srcPrinterJob, jm_getSelectAttrib); - if (selectID ==0) { - [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages]; - } else if (selectID == 2) { - // In Mac 10.7, Print ALL is deselected if PrintSelection is YES whether - // NSPrintAllPages is YES or NO - [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages]; - [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintSelectionOnly]; - } else { - [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages]; - } - - jint fromPage = JNFCallIntMethod(env, srcPrinterJob, jm_getFromPage); - jint toPage = JNFCallIntMethod(env, srcPrinterJob, jm_getToPage); - // setting fromPage and toPage will not be shown in the dialog if printing All pages - [printingDictionary setObject:[NSNumber numberWithInteger:fromPage] forKey:NSPrintFirstPage]; - [printingDictionary setObject:[NSNumber numberWithInteger:toPage] forKey:NSPrintLastPage]; - } - else - { + jint selectID = JNFCallIntMethod(env, srcPrinterJob, jm_getSelectAttrib); + jint fromPage = JNFCallIntMethod(env, srcPrinterJob, jm_getFromPage); + jint toPage = JNFCallIntMethod(env, srcPrinterJob, jm_getToPage); + if (selectID ==0) { [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages]; + } else if (selectID == 2) { + // In Mac 10.7, Print ALL is deselected if PrintSelection is YES whether + // NSPrintAllPages is YES or NO + [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages]; + [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintSelectionOnly]; + } else { + jint minPage = JNFCallIntMethod(env, srcPrinterJob, jm_getMinPage); + jint maxPage = JNFCallIntMethod(env, srcPrinterJob, jm_getMaxPage); + + // for PD_SELECTION or PD_NOSELECTION, check from/to page + // to determine which radio button to select + if (fromPage > minPage || toPage < maxPage) { + [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages]; + } else { + [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages]; + } } + + // setting fromPage and toPage will not be shown in the dialog if printing All pages + [printingDictionary setObject:[NSNumber numberWithInteger:fromPage] forKey:NSPrintFirstPage]; + [printingDictionary setObject:[NSNumber numberWithInteger:toPage] forKey:NSPrintLastPage]; + jobject page = JNFCallObjectMethod(env, srcPrinterJob, jm_getPageFormat); if (page != NULL) { javaPageFormatToNSPrintInfo(env, NULL, page, dst); diff --git a/jdk/test/java/awt/print/PrinterJob/DlgAttrsBug.java b/jdk/test/java/awt/print/PrinterJob/DlgAttrsBug.java new file mode 100644 index 00000000000..dc31ffda1fd --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/DlgAttrsBug.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8061258 + * @summary PrinterJob's native Print Dialog does not reflect + * specified Copies or Page Ranges + * @run main/manual DlgAttrsBug + */ +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.DialogTypeSelection; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + + +public class DlgAttrsBug implements Printable { + private static Thread mainThread; + private static boolean testPassed; + private static boolean testGeneratedInterrupt; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + doTest(DlgAttrsBug::printTest); + }); + mainThread = Thread.currentThread(); + try { + Thread.sleep(30000); + } catch (InterruptedException e) { + if (!testPassed && testGeneratedInterrupt) { + throw new RuntimeException("Print Dialog does not " + + "reflect Copies or Page Ranges"); + } + } + if (!testGeneratedInterrupt) { + throw new RuntimeException("user has not executed the test"); + } + } + + private static void printTest() { + PrinterJob job = PrinterJob.getPrinterJob(); + if (job.getPrintService() == null) { + System.out.println("No printers. Test cannot continue"); + return; + } + job.setPrintable(new DlgAttrsBug()); + PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); + aset.add(new Copies(5)); + aset.add(new PageRanges(3,4)); + aset.add(DialogTypeSelection.NATIVE); + job.printDialog(aset); + } + + public static synchronized void pass() { + testPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + public static synchronized void fail() { + testPassed = false; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + private static void doTest(Runnable action) { + String description + = " Visual inspection of print dialog is required.\n" + + " A print dialog will be shown.\n " + + " Please verify Copies 5 is selected.\n" + + " Also verify, Page Range is selected with " + + " from page 3 and to Page 4.\n" + + " If ok, press PASS else press FAIL"; + + final JDialog dialog = new JDialog(); + dialog.setTitle("printSelectionTest"); + JTextArea textArea = new JTextArea(description); + textArea.setEditable(false); + final JButton testButton = new JButton("Start Test"); + final JButton passButton = new JButton("PASS"); + passButton.setEnabled(false); + passButton.addActionListener((e) -> { + dialog.dispose(); + pass(); + }); + final JButton failButton = new JButton("FAIL"); + failButton.setEnabled(false); + failButton.addActionListener((e) -> { + dialog.dispose(); + fail(); + }); + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + action.run(); + passButton.setEnabled(true); + failButton.setEnabled(true); + }); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + dialog.pack(); + dialog.setVisible(true); + } + + public int print(Graphics g, PageFormat pf, int pi) + throws PrinterException { + System.out.println("pi = " + pi); + if (pi >= 5) { + return NO_SUCH_PAGE; + } + g.drawString("Page : " + (pi+1), 200, 200); + return PAGE_EXISTS; + } + +} From dfbe023cec5a5159f8787993ebe2adb4342c3607 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 30 Mar 2016 17:17:00 +0530 Subject: [PATCH 037/222] 8042713: [macosx] Print dialog does not update attribute set with page range Reviewed-by: prr, jdv --- .../classes/sun/lwawt/macosx/CPrinterJob.java | 40 +++++++- .../native/libawt_lwawt/awt/CPrinterJob.m | 14 ++- .../PrinterJob/PrintAttributeUpdateTest.java | 91 +++++++++++++++++++ 3 files changed, 137 insertions(+), 8 deletions(-) create mode 100644 jdk/test/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index 491b257765f..aa00647de21 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -36,6 +36,7 @@ import java.security.PrivilegedAction; import javax.print.*; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.Media; import javax.print.attribute.standard.MediaPrintableArea; import javax.print.attribute.standard.MediaSize; @@ -194,10 +195,37 @@ public final class CPrinterJob extends RasterPrinterJob { // setPageRange will set firstPage and lastPage as called in getFirstPage // and getLastPage setPageRange(range[0][0] - 1, range[0][1] - 1); + } else { + // if rangeSelect is SunPageSelection.ALL + // then setPageRange appropriately + setPageRange(-1, -1); } } } + private void setPageRangeAttribute(int from, int to, boolean isRangeSet) { + if (attributes != null) { + // since native Print use zero-based page indices, + // we need to store in 1-based format in attributes set + // but setPageRange again uses zero-based indices so it should be + // 1 less than pageRanges attribute + if (isRangeSet) { + attributes.add(new PageRanges(from+1, to+1)); + attributes.add(SunPageSelection.RANGE); + setPageRange(from, to); + } else { + attributes.add(SunPageSelection.ALL); + } + } + } + + private void setCopiesAttribute(int copies) { + if (attributes != null) { + attributes.add(new Copies(copies)); + super.setCopies(copies); + } + } + volatile boolean onEventThread; @Override @@ -691,9 +719,15 @@ public final class CPrinterJob extends RasterPrinterJob { if (pageFormat != null) { Printable printable = pageable.getPrintable(pageIndex); if (printable != null) { - BufferedImage bimg = new BufferedImage((int)Math.round(pageFormat.getWidth()), (int)Math.round(pageFormat.getHeight()), BufferedImage.TYPE_INT_ARGB_PRE); - PeekGraphics peekGraphics = createPeekGraphics(bimg.createGraphics(), printerJob); - Rectangle2D pageFormatArea = getPageFormatArea(pageFormat); + BufferedImage bimg = + new BufferedImage( + (int)Math.round(pageFormat.getWidth()), + (int)Math.round(pageFormat.getHeight()), + BufferedImage.TYPE_INT_ARGB_PRE); + PeekGraphics peekGraphics = + createPeekGraphics(bimg.createGraphics(), printerJob); + Rectangle2D pageFormatArea = + getPageFormatArea(pageFormat); initPrinterGraphics(peekGraphics, pageFormatArea); // Do the assignment here! diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m index b1428528730..03a32ddd8e7 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m @@ -312,9 +312,9 @@ static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrintJob, jobjec static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable) { static JNF_MEMBER_CACHE(jm_setService, sjc_CPrinterJob, "setPrinterServiceFromNative", "(Ljava/lang/String;)V"); - static JNF_MEMBER_CACHE(jm_setCopies, sjc_CPrinterJob, "setCopies", "(I)V"); + static JNF_MEMBER_CACHE(jm_setCopiesAttribute, sjc_CPrinterJob, "setCopiesAttribute", "(I)V"); static JNF_MEMBER_CACHE(jm_setCollated, sjc_CPrinterJob, "setCollated", "(Z)V"); - static JNF_MEMBER_CACHE(jm_setPageRange, sjc_CPrinterJob, "setPageRange", "(II)V"); + static JNF_MEMBER_CACHE(jm_setPageRangeAttribute, sjc_CPrinterJob, "setPageRangeAttribute", "(IIZ)V"); // get the selected printer's name, and set the appropriate PrintService on the Java side NSString *name = [[src printer] name]; @@ -327,7 +327,7 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d NSNumber* nsCopies = [printingDictionary objectForKey:NSPrintCopies]; if ([nsCopies respondsToSelector:@selector(integerValue)]) { - JNFCallVoidMethod(env, dstPrinterJob, jm_setCopies, [nsCopies integerValue]); // AWT_THREADING Safe (known object) + JNFCallVoidMethod(env, dstPrinterJob, jm_setCopiesAttribute, [nsCopies integerValue]); // AWT_THREADING Safe (known object) } NSNumber* nsCollated = [printingDictionary objectForKey:NSPrintMustCollate]; @@ -340,6 +340,7 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d if ([nsPrintAllPages respondsToSelector:@selector(boolValue)]) { jint jFirstPage = 0, jLastPage = java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES; + jboolean isRangeSet = false; if (![nsPrintAllPages boolValue]) { NSNumber* nsFirstPage = [printingDictionary objectForKey:NSPrintFirstPage]; @@ -353,9 +354,12 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d { jLastPage = [nsLastPage integerValue] - 1; } - } + isRangeSet = true; + } + JNFCallVoidMethod(env, dstPrinterJob, jm_setPageRangeAttribute, + jFirstPage, jLastPage, isRangeSet); + // AWT_THREADING Safe (known object) - JNFCallVoidMethod(env, dstPrinterJob, jm_setPageRange, jFirstPage, jLastPage); // AWT_THREADING Safe (known object) } } diff --git a/jdk/test/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java b/jdk/test/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java new file mode 100644 index 00000000000..f068964c4e1 --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8042713 + @summary Print Dialog does not update attribute set with page range + @run main/manual PrintAttributeUpdateTest + */ +import java.awt.Component; +import java.awt.Graphics; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Printable; +import java.awt.print.PrinterJob; +import javax.print.attribute.Attribute; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.standard.DialogTypeSelection; +import javax.print.attribute.standard.PageRanges; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +public class PrintAttributeUpdateTest implements Pageable, Printable { + + public static void main(String args[]) throws Exception { + String[] instructions + = { + "Select Pages Range From instead of All in print dialog. ", + "Then select Print" + }; + SwingUtilities.invokeAndWait(() -> { + JOptionPane.showMessageDialog((Component) null, + instructions, "Instructions", + JOptionPane.INFORMATION_MESSAGE); + }); + HashPrintRequestAttributeSet as = new HashPrintRequestAttributeSet(); + PrinterJob j = PrinterJob.getPrinterJob(); + j.setPageable(new PrintAttributeUpdateTest()); + as.add(DialogTypeSelection.NATIVE); + j.printDialog(as); + if (as.containsKey(PageRanges.class) == false) { + throw new RuntimeException("Print Dialog did not update " + + " attribute set with page range"); + } + Attribute attrs[] = as.toArray(); + for (int i = 0; i < attrs.length; i++) { + System.out.println("attr " + attrs[i]); + } + j.print(as); + } + + public int getNumberOfPages() { + return UNKNOWN_NUMBER_OF_PAGES; + } + + public PageFormat getPageFormat(int pageIndex) { + PageFormat pf = new PageFormat(); + return pf; + } + + public Printable getPrintable(int pageIndex) { + return this; + } + + public int print(Graphics g, PageFormat pgFmt, int pi) { + g.drawString("Page : " + (pi + 1), 200, 200); + + return PAGE_EXISTS; + } + +} From e7e8e6904f7222cf9fe4d74119e0bf6a1d62c3ac Mon Sep 17 00:00:00 2001 From: Ajit Ghaisas Date: Thu, 31 Mar 2016 15:30:05 +0530 Subject: [PATCH 038/222] 6353518: Creation of a WritableRaster with a custom DataBuffer causes erroneous Exception Reviewed-by: serb, prr, flar --- .../classes/sun/java2d/IntegerNIORaster.java | 12 +- .../share/classes/java/awt/image/Raster.java | 178 ++++++--- .../sun/awt/image/ByteBandedRaster.java | 35 +- .../sun/awt/image/ByteComponentRaster.java | 37 +- .../sun/awt/image/ByteInterleavedRaster.java | 35 +- .../sun/awt/image/BytePackedRaster.java | 35 +- .../sun/awt/image/IntegerComponentRaster.java | 36 +- .../awt/image/IntegerInterleavedRaster.java | 34 +- .../sun/awt/image/ShortBandedRaster.java | 34 +- .../sun/awt/image/ShortComponentRaster.java | 34 +- .../sun/awt/image/ShortInterleavedRaster.java | 31 +- .../java/awt/image/RasterCreationTest.java | 352 ++++++++++++++++++ 12 files changed, 621 insertions(+), 232 deletions(-) create mode 100644 jdk/test/java/awt/image/RasterCreationTest.java diff --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/IntegerNIORaster.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/IntegerNIORaster.java index 59101b74006..e2dfcf20d73 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/IntegerNIORaster.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/IntegerNIORaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ public class IntegerNIORaster extends SunWritableRaster { ") cannot be <= 0"); } // This is cribbed from java.awt.image.Raster. - DataBuffer db = new DataBufferNIOInt(w * h); + DataBufferNIOInt db = new DataBufferNIOInt(w * h); if (location == null) { location = new Point(0, 0); } @@ -48,13 +48,11 @@ public class IntegerNIORaster extends SunWritableRaster { return new IntegerNIORaster(sppsm, db, location); } - public IntegerNIORaster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) { + public IntegerNIORaster(SampleModel sampleModel, DataBufferNIOInt dataBuffer, Point origin) { // This is all cribbed from sun.awt.image.IntegerInterleavedRaster & sun.awt.image.IntegerComponentRaster super(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.getWidth(), sampleModel.getHeight()), origin, null); - if (!(dataBuffer instanceof DataBufferNIOInt)) { - throw new RasterFormatException("IntegerNIORasters must have DataBufferNIOInt DataBuffers"); - } - this.data = ((DataBufferNIOInt)dataBuffer).getBuffer(); + + this.data = dataBuffer.getBuffer(); } public WritableRaster createCompatibleWritableRaster() { diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/Raster.java b/jdk/src/java.desktop/share/classes/java/awt/image/Raster.java index f5a36d10a47..c7aca57eed8 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/image/Raster.java +++ b/jdk/src/java.desktop/share/classes/java/awt/image/Raster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -629,7 +629,8 @@ public class Raster { int scanlineStride, int pixelStride, int bandOffsets[], - Point location) { + Point location) + { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } @@ -645,15 +646,26 @@ public class Raster { bandOffsets); switch(dataType) { case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(csm, dataBuffer, location); + if (dataBuffer instanceof DataBufferByte) { + return new ByteInterleavedRaster(csm, + (DataBufferByte) dataBuffer, location); + } + break; case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(csm, dataBuffer, location); + if (dataBuffer instanceof DataBufferUShort) { + return new ShortInterleavedRaster(csm, + (DataBufferUShort) dataBuffer, location); + } + break; default: throw new IllegalArgumentException("Unsupported data type " + dataType); } + + // Create the generic raster + return new SunWritableRaster(csm, dataBuffer, location); } /** @@ -691,7 +703,8 @@ public class Raster { int scanlineStride, int bankIndices[], int bandOffsets[], - Point location) { + Point location) + { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } @@ -713,18 +726,29 @@ public class Raster { switch(dataType) { case DataBuffer.TYPE_BYTE: - return new ByteBandedRaster(bsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferByte) { + return new ByteBandedRaster(bsm, + (DataBufferByte) dataBuffer, location); + } + break; case DataBuffer.TYPE_USHORT: - return new ShortBandedRaster(bsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferUShort) { + return new ShortBandedRaster(bsm, + (DataBufferUShort) dataBuffer, location); + } + break; case DataBuffer.TYPE_INT: - return new SunWritableRaster(bsm, dataBuffer, location); + break; default: throw new IllegalArgumentException("Unsupported data type " + dataType); } + + // Create the generic raster + return new SunWritableRaster(bsm, dataBuffer, location); } /** @@ -761,7 +785,8 @@ public class Raster { int w, int h, int scanlineStride, int bandMasks[], - Point location) { + Point location) + { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } @@ -776,18 +801,33 @@ public class Raster { switch(dataType) { case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sppsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferByte) { + return new ByteInterleavedRaster(sppsm, + (DataBufferByte) dataBuffer, location); + } + break; case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sppsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sppsm, + (DataBufferUShort) dataBuffer, location); + } + break; case DataBuffer.TYPE_INT: - return new IntegerInterleavedRaster(sppsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferInt) { + return new IntegerInterleavedRaster(sppsm, + (DataBufferInt) dataBuffer, location); + } + break; default: throw new IllegalArgumentException("Unsupported data type " + dataType); } + + // Create the generic raster + return new SunWritableRaster(sppsm, dataBuffer, location); } /** @@ -821,7 +861,8 @@ public class Raster { public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h, int bitsPerPixel, - Point location) { + Point location) + { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } @@ -846,9 +887,10 @@ public class Raster { MultiPixelPackedSampleModel mppsm = new MultiPixelPackedSampleModel(dataType, w, h, bitsPerPixel); - if (dataType == DataBuffer.TYPE_BYTE && - (bitsPerPixel == 1 || bitsPerPixel == 2 || bitsPerPixel == 4)) { - return new BytePackedRaster(mppsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferByte && + (bitsPerPixel == 1 || bitsPerPixel == 2 || bitsPerPixel == 4)) + { + return new BytePackedRaster(mppsm, (DataBufferByte) dataBuffer, location); } else { return new SunWritableRaster(mppsm, dataBuffer, location); } @@ -878,7 +920,8 @@ public class Raster { */ public static Raster createRaster(SampleModel sm, DataBuffer db, - Point location) { + Point location) + { if ((sm == null) || (db == null)) { throw new NullPointerException("SampleModel and DataBuffer cannot be null"); } @@ -890,32 +933,53 @@ public class Raster { if (sm instanceof PixelInterleavedSampleModel) { switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_BYTE: + if (db instanceof DataBufferByte) { + return new ByteInterleavedRaster(sm, + (DataBufferByte) db, location); + } + break; - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_USHORT: + if (db instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sm, + (DataBufferUShort) db, location); + } + break; } } else if (sm instanceof SinglePixelPackedSampleModel) { switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_BYTE: + if (db instanceof DataBufferByte) { + return new ByteInterleavedRaster(sm, + (DataBufferByte) db, location); + } + break; - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_USHORT: + if (db instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sm, + (DataBufferUShort) db, location); + } + break; - case DataBuffer.TYPE_INT: - return new IntegerInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_INT: + if (db instanceof DataBufferInt) { + return new IntegerInterleavedRaster(sm, + (DataBufferInt) db, location); + } + break; } } else if (sm instanceof MultiPixelPackedSampleModel && dataType == DataBuffer.TYPE_BYTE && - sm.getSampleSize(0) < 8) { - return new BytePackedRaster(sm, db, location); + db instanceof DataBufferByte && + sm.getSampleSize(0) < 8) + { + return new BytePackedRaster(sm, (DataBufferByte) db, location); } // we couldn't do anything special - do the generic thing - - return new Raster(sm,db,location); + return new Raster(sm, db, location); } /** @@ -964,7 +1028,8 @@ public class Raster { */ public static WritableRaster createWritableRaster(SampleModel sm, DataBuffer db, - Point location) { + Point location) + { if ((sm == null) || (db == null)) { throw new NullPointerException("SampleModel and DataBuffer cannot be null"); } @@ -976,32 +1041,53 @@ public class Raster { if (sm instanceof PixelInterleavedSampleModel) { switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_BYTE: + if (db instanceof DataBufferByte) { + return new ByteInterleavedRaster(sm, + (DataBufferByte) db, location); + } + break; - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_USHORT: + if (db instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sm, + (DataBufferUShort) db, location); + } + break; } } else if (sm instanceof SinglePixelPackedSampleModel) { switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_BYTE: + if (db instanceof DataBufferByte) { + return new ByteInterleavedRaster(sm, + (DataBufferByte) db, location); + } + break; - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_USHORT: + if (db instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sm, + (DataBufferUShort) db, location); + } + break; - case DataBuffer.TYPE_INT: - return new IntegerInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_INT: + if (db instanceof DataBufferInt) { + return new IntegerInterleavedRaster(sm, + (DataBufferInt) db, location); + } + break; } } else if (sm instanceof MultiPixelPackedSampleModel && dataType == DataBuffer.TYPE_BYTE && - sm.getSampleSize(0) < 8) { - return new BytePackedRaster(sm, db, location); + db instanceof DataBufferByte && + sm.getSampleSize(0) < 8) + { + return new BytePackedRaster(sm, (DataBufferByte) db, location); } // we couldn't do anything special - do the generic thing - - return new SunWritableRaster(sm,db,location); + return new SunWritableRaster(sm, db, location); } /** diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java index 699c1ea2f43..1123a9f69fd 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * 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,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.BandedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.Rectangle; import java.awt.Point; @@ -74,10 +73,9 @@ public class ByteBandedRaster extends SunWritableRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specifies the origin. */ - public ByteBandedRaster(SampleModel sampleModel, - Point origin) { + public ByteBandedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferByte) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -93,12 +91,13 @@ public class ByteBandedRaster extends SunWritableRaster { * initialized and must be a DataBufferShort compatible with SampleModel. * SampleModel must be of type BandedSampleModel. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param origin The Point that specifies the origin. */ public ByteBandedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferByte dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x , origin.y, sampleModel.getWidth(), @@ -119,39 +118,33 @@ public class ByteBandedRaster extends SunWritableRaster { * Note that this constructor should generally be called by other * constructors or create methods, it should not be used directly. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param aRegion The Rectangle that specifies the image area. * @param origin The Point that specifies the origin. * @param parent The parent (if any) of this raster. */ public ByteBandedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, + DataBufferByte dataBuffer, Rectangle aRegion, Point origin, - ByteBandedRaster parent) { - + ByteBandedRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferByte)) { - throw new RasterFormatException("ByteBandedRaster must have" + - "byte DataBuffers"); - } - DataBufferByte dbb = (DataBufferByte)dataBuffer; - if (sampleModel instanceof BandedSampleModel) { BandedSampleModel bsm = (BandedSampleModel)sampleModel; this.scanlineStride = bsm.getScanlineStride(); int bankIndices[] = bsm.getBankIndices(); int bandOffsets[] = bsm.getBandOffsets(); - int dOffsets[] = dbb.getOffsets(); + int dOffsets[] = dataBuffer.getOffsets(); dataOffsets = new int[bankIndices.length]; data = new byte[bankIndices.length][]; int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; for (int i = 0; i < bankIndices.length; i++) { - data[i] = stealData(dbb, bankIndices[i]); + data[i] = stealData(dataBuffer, bankIndices[i]); dataOffsets[i] = dOffsets[bankIndices[i]] + xOffset + yOffset*scanlineStride + bandOffsets[i]; } @@ -672,7 +665,7 @@ public class ByteBandedRaster extends SunWritableRaster { int deltaY = y0 - y; return new ByteBandedRaster(sm, - dataBuffer, + (DataBufferByte) dataBuffer, new Rectangle(x0,y0,width,height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java index 673e51d8518..f284e3b1fc4 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.ComponentSampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.Rectangle; import java.awt.Point; @@ -94,7 +93,7 @@ public class ByteComponentRaster extends SunWritableRaster { */ public ByteComponentRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferByte) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -111,12 +110,13 @@ public class ByteComponentRaster extends SunWritableRaster { * SampleModel must be of type SinglePixelPackedSampleModel * or ComponentSampleModel. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param origin The Point that specifies the origin. */ public ByteComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferByte dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -141,33 +141,28 @@ public class ByteComponentRaster extends SunWritableRaster { * Note that this constructor should generally be called by other * constructors or create methods, it should not be used directly. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param aRegion The Rectangle that specifies the image area. * @param origin The Point that specifies the origin. * @param parent The parent (if any) of this raster. */ public ByteComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ByteComponentRaster parent) { + DataBufferByte dataBuffer, + Rectangle aRegion, + Point origin, + ByteComponentRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferByte)) { - throw new RasterFormatException("ByteComponentRasters must have " + - "byte DataBuffers"); - } - - DataBufferByte dbb = (DataBufferByte)dataBuffer; - this.data = stealData(dbb, 0); - if (dbb.getNumBanks() != 1) { + this.data = stealData(dataBuffer, 0); + if (dataBuffer.getNumBanks() != 1) { throw new RasterFormatException("DataBuffer for ByteComponentRasters"+ " must only have 1 bank."); } - int dbOffset = dbb.getOffset(); + int dbOffset = dataBuffer.getOffset(); if (sampleModel instanceof ComponentSampleModel) { ComponentSampleModel ism = (ComponentSampleModel)sampleModel; @@ -823,7 +818,7 @@ public class ByteComponentRaster extends SunWritableRaster { int deltaY = y0 - y; return new ByteComponentRaster(sm, - dataBuffer, + (DataBufferByte) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java index 52f01b30b63..b406fb65211 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.awt.image.SampleModel; import java.awt.image.ComponentSampleModel; import java.awt.image.PixelInterleavedSampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.Rectangle; import java.awt.Point; @@ -87,7 +86,7 @@ public class ByteInterleavedRaster extends ByteComponentRaster { */ public ByteInterleavedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferByte) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -104,12 +103,13 @@ public class ByteInterleavedRaster extends ByteComponentRaster { * SampleModel must be of type SinglePixelPackedSampleModel * or InterleavedSampleModel. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param origin The Point that specifies the origin. */ public ByteInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferByte dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -178,27 +178,22 @@ public class ByteInterleavedRaster extends ByteComponentRaster { * Note that this constructor should generally be called by other * constructors or create methods, it should not be used directly. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param aRegion The Rectangle that specifies the image area. * @param origin The Point that specifies the origin. * @param parent The parent (if any) of this raster. */ public ByteInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ByteInterleavedRaster parent) { + DataBufferByte dataBuffer, + Rectangle aRegion, + Point origin, + ByteInterleavedRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferByte)) { - throw new RasterFormatException("ByteInterleavedRasters must have " + - "byte DataBuffers"); - } - - DataBufferByte dbb = (DataBufferByte)dataBuffer; - this.data = stealData(dbb, 0); + this.data = stealData(dataBuffer, 0); int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; @@ -221,7 +216,7 @@ public class ByteInterleavedRaster extends ByteComponentRaster { this.scanlineStride = sppsm.getScanlineStride(); this.pixelStride = 1; this.dataOffsets = new int[1]; - this.dataOffsets[0] = dbb.getOffset(); + this.dataOffsets[0] = dataBuffer.getOffset(); dataOffsets[0] += xOffset*pixelStride+yOffset*scanlineStride; } else { throw new RasterFormatException("ByteInterleavedRasters must " + @@ -1259,7 +1254,7 @@ public class ByteInterleavedRaster extends ByteComponentRaster { int deltaY = y0 - y; return new ByteInterleavedRaster(sm, - dataBuffer, + (DataBufferByte) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java index f9696c17eb8..ac00075c16a 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * 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,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.MultiPixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.Rectangle; import java.awt.Point; @@ -89,10 +88,9 @@ public class BytePackedRaster extends SunWritableRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specified the origin. */ - public BytePackedRaster(SampleModel sampleModel, - Point origin) { + public BytePackedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferByte) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -108,12 +106,13 @@ public class BytePackedRaster extends SunWritableRaster { * initialized and must be a DataBufferByte compatible with SampleModel. * SampleModel must be of type MultiPixelPackedSampleModel. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param origin The Point that specifies the origin. */ public BytePackedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferByte dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -137,7 +136,7 @@ public class BytePackedRaster extends SunWritableRaster { * Note that this constructor should generally be called by other * constructors or create methods, it should not be used directly. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param aRegion The Rectangle that specifies the image area. * @param origin The Point that specifies the origin. * @param parent The parent (if any) of this raster. @@ -146,26 +145,22 @@ public class BytePackedRaster extends SunWritableRaster { * to requirements of this Raster type. */ public BytePackedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, + DataBufferByte dataBuffer, Rectangle aRegion, Point origin, - BytePackedRaster parent){ + BytePackedRaster parent) + { super(sampleModel,dataBuffer,aRegion,origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferByte)) { - throw new RasterFormatException("BytePackedRasters must have" + - "byte DataBuffers"); - } - DataBufferByte dbb = (DataBufferByte)dataBuffer; - this.data = stealData(dbb, 0); - if (dbb.getNumBanks() != 1) { + this.data = stealData(dataBuffer, 0); + if (dataBuffer.getNumBanks() != 1) { throw new RasterFormatException("DataBuffer for BytePackedRasters"+ " must only have 1 bank."); } - int dbOffset = dbb.getOffset(); + int dbOffset = dataBuffer.getOffset(); if (sampleModel instanceof MultiPixelPackedSampleModel) { MultiPixelPackedSampleModel mppsm = @@ -1322,7 +1317,7 @@ public class BytePackedRaster extends SunWritableRaster { int deltaY = y0 - y; return new BytePackedRaster(sm, - dataBuffer, + (DataBufferByte) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java index cd84986b77f..44ab7253083 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * 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,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferInt; import java.awt.Rectangle; import java.awt.Point; @@ -107,10 +106,9 @@ public class IntegerComponentRaster extends SunWritableRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specified the origin. */ - public IntegerComponentRaster(SampleModel sampleModel, - Point origin) { + public IntegerComponentRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferInt) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -130,8 +128,9 @@ public class IntegerComponentRaster extends SunWritableRaster { * @param origin The Point that specifies the origin. */ public IntegerComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferInt dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -161,24 +160,21 @@ public class IntegerComponentRaster extends SunWritableRaster { * @param parent The parent (if any) of this raster. */ public IntegerComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - IntegerComponentRaster parent){ + DataBufferInt dataBuffer, + Rectangle aRegion, + Point origin, + IntegerComponentRaster parent) + { super(sampleModel,dataBuffer,aRegion,origin,parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferInt)) { - throw new RasterFormatException("IntegerComponentRasters must have" + - "integer DataBuffers"); - } - DataBufferInt dbi = (DataBufferInt)dataBuffer; - if (dbi.getNumBanks() != 1) { + + if (dataBuffer.getNumBanks() != 1) { throw new RasterFormatException("DataBuffer for IntegerComponentRasters"+ " must only have 1 bank."); } - this.data = stealData(dbi, 0); + this.data = stealData(dataBuffer, 0); if (sampleModel instanceof SinglePixelPackedSampleModel) { SinglePixelPackedSampleModel sppsm = @@ -197,7 +193,7 @@ public class IntegerComponentRaster extends SunWritableRaster { this.scanlineStride = sppsm.getScanlineStride(); this.pixelStride = 1; this.dataOffsets = new int[1]; - this.dataOffsets[0] = dbi.getOffset(); + this.dataOffsets[0] = dataBuffer.getOffset(); this.bandOffset = this.dataOffsets[0]; int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; @@ -569,7 +565,7 @@ public class IntegerComponentRaster extends SunWritableRaster { int deltaY = y0 - y; return new IntegerComponentRaster(sm, - dataBuffer, + (DataBufferInt) dataBuffer, new Rectangle(x0,y0,width,height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java index a852080a701..48ec3eed7ad 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * 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,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferInt; import java.awt.Rectangle; import java.awt.Point; @@ -67,10 +66,9 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specified the origin. */ - public IntegerInterleavedRaster(SampleModel sampleModel, - Point origin) { + public IntegerInterleavedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferInt) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -90,8 +88,9 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { * @param origin The Point that specifies the origin. */ public IntegerInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferInt dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -121,19 +120,16 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { * @param parent The parent (if any) of this raster. */ public IntegerInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - IntegerInterleavedRaster parent){ + DataBufferInt dataBuffer, + Rectangle aRegion, + Point origin, + IntegerInterleavedRaster parent) + { super(sampleModel,dataBuffer,aRegion,origin,parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferInt)) { - throw new RasterFormatException("IntegerInterleavedRasters must have" + - "integer DataBuffers"); - } - DataBufferInt dbi = (DataBufferInt)dataBuffer; - this.data = stealData(dbi, 0); + + this.data = stealData(dataBuffer, 0); if (sampleModel instanceof SinglePixelPackedSampleModel) { SinglePixelPackedSampleModel sppsm = @@ -141,7 +137,7 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { this.scanlineStride = sppsm.getScanlineStride(); this.pixelStride = 1; this.dataOffsets = new int[1]; - this.dataOffsets[0] = dbi.getOffset(); + this.dataOffsets[0] = dataBuffer.getOffset(); this.bandOffset = this.dataOffsets[0]; int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; @@ -481,7 +477,7 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { int deltaY = y0 - y; return new IntegerInterleavedRaster(sm, - dataBuffer, + (DataBufferInt) dataBuffer, new Rectangle(x0,y0,width,height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java index fd5c610504d..6222c61b5e9 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * 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,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.BandedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferUShort; import java.awt.Rectangle; import java.awt.Point; @@ -72,10 +71,9 @@ public class ShortBandedRaster extends SunWritableRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specified the origin. */ - public ShortBandedRaster(SampleModel sampleModel, - Point origin) { + public ShortBandedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferUShort) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -95,8 +93,9 @@ public class ShortBandedRaster extends SunWritableRaster { * @param origin The Point that specifies the origin. */ public ShortBandedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferUShort dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -123,32 +122,27 @@ public class ShortBandedRaster extends SunWritableRaster { * @param parent The parent (if any) of this raster. */ public ShortBandedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ShortBandedRaster parent) { - + DataBufferUShort dataBuffer, + Rectangle aRegion, + Point origin, + ShortBandedRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferUShort)) { - throw new RasterFormatException("ShortBandedRaster must have " + - "ushort DataBuffers"); - } - DataBufferUShort dbus = (DataBufferUShort)dataBuffer; if (sampleModel instanceof BandedSampleModel) { BandedSampleModel bsm = (BandedSampleModel)sampleModel; this.scanlineStride = bsm.getScanlineStride(); int bankIndices[] = bsm.getBankIndices(); int bandOffsets[] = bsm.getBandOffsets(); - int dOffsets[] = dbus.getOffsets(); + int dOffsets[] = dataBuffer.getOffsets(); dataOffsets = new int[bankIndices.length]; data = new short[bankIndices.length][]; int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; for (int i = 0; i < bankIndices.length; i++) { - data[i] = stealData(dbus, bankIndices[i]); + data[i] = stealData(dataBuffer, bankIndices[i]); dataOffsets[i] = dOffsets[bankIndices[i]] + xOffset + yOffset*scanlineStride + bandOffsets[i]; } @@ -670,7 +664,7 @@ public class ShortBandedRaster extends SunWritableRaster { int deltaY = y0 - y; return new ShortBandedRaster(sm, - dataBuffer, + (DataBufferUShort) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java index 76ab7d75ce4..79016e9df5a 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.ComponentSampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferUShort; import java.awt.Rectangle; import java.awt.Point; @@ -94,7 +93,7 @@ public class ShortComponentRaster extends SunWritableRaster { */ public ShortComponentRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferUShort) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -115,8 +114,9 @@ public class ShortComponentRaster extends SunWritableRaster { * @param origin The Point that specifies the origin. */ public ShortComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferUShort dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -146,28 +146,22 @@ public class ShortComponentRaster extends SunWritableRaster { * @param parent The parent (if any) of this raster. */ public ShortComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ShortComponentRaster parent) { - + DataBufferUShort dataBuffer, + Rectangle aRegion, + Point origin, + ShortComponentRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if(!(dataBuffer instanceof DataBufferUShort)) { - throw new RasterFormatException("ShortComponentRasters must have "+ - "short DataBuffers"); - } - - DataBufferUShort dbus = (DataBufferUShort)dataBuffer; - this.data = stealData(dbus, 0); - if (dbus.getNumBanks() != 1) { + this.data = stealData(dataBuffer, 0); + if (dataBuffer.getNumBanks() != 1) { throw new RasterFormatException("DataBuffer for ShortComponentRasters"+ " must only have 1 bank."); } - int dbOffset = dbus.getOffset(); + int dbOffset = dataBuffer.getOffset(); if (sampleModel instanceof ComponentSampleModel) { ComponentSampleModel csm = (ComponentSampleModel)sampleModel; @@ -758,7 +752,7 @@ public class ShortComponentRaster extends SunWritableRaster { int deltaY = y0 - y; return new ShortComponentRaster(sm, - dataBuffer, + (DataBufferUShort) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java index 05310891fe5..7a1644b6275 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.awt.image.SampleModel; import java.awt.image.ComponentSampleModel; import java.awt.image.PixelInterleavedSampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferUShort; import java.awt.Rectangle; import java.awt.Point; @@ -71,7 +70,7 @@ public class ShortInterleavedRaster extends ShortComponentRaster { */ public ShortInterleavedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferUShort) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -92,8 +91,9 @@ public class ShortInterleavedRaster extends ShortComponentRaster { * @param origin The Point that specifies the origin. */ public ShortInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferUShort dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -123,22 +123,17 @@ public class ShortInterleavedRaster extends ShortComponentRaster { * @param parent The parent (if any) of this raster. */ public ShortInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ShortInterleavedRaster parent) { + DataBufferUShort dataBuffer, + Rectangle aRegion, + Point origin, + ShortInterleavedRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if(!(dataBuffer instanceof DataBufferUShort)) { - throw new RasterFormatException("ShortInterleavedRasters must "+ - "have ushort DataBuffers"); - } - - DataBufferUShort dbus = (DataBufferUShort)dataBuffer; - this.data = stealData(dbus, 0); + this.data = stealData(dataBuffer, 0); // REMIND: need case for interleaved ComponentSampleModel if ((sampleModel instanceof PixelInterleavedSampleModel) || @@ -160,7 +155,7 @@ public class ShortInterleavedRaster extends ShortComponentRaster { this.scanlineStride = sppsm.getScanlineStride(); this.pixelStride = 1; this.dataOffsets = new int[1]; - this.dataOffsets[0] = dbus.getOffset(); + this.dataOffsets[0] = dataBuffer.getOffset(); int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; dataOffsets[0] += xOffset+yOffset*scanlineStride; @@ -730,7 +725,7 @@ public class ShortInterleavedRaster extends ShortComponentRaster { int deltaY = y0 - y; return new ShortInterleavedRaster(sm, - dataBuffer, + (DataBufferUShort) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/test/java/awt/image/RasterCreationTest.java b/jdk/test/java/awt/image/RasterCreationTest.java new file mode 100644 index 00000000000..885fb8da76d --- /dev/null +++ b/jdk/test/java/awt/image/RasterCreationTest.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.awt.Point; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferDouble; +import java.awt.image.DataBufferFloat; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.DataBufferUShort; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.PixelInterleavedSampleModel; +import java.awt.image.SinglePixelPackedSampleModel; + +/* + * @test + * @bug 6353518 + * @summary Test possible combinations of Raster creation + * Test fails if any of Raster.createXXX() method throws exception. + */ +public class RasterCreationTest { + + public static void main(String[] args) { + + final int width = 10; + final int height = 5; + final int imageSize = width * height; + Point location = new Point(0, 0); + int[] bandOffsets = {0}; + int[] bitMask = {0x00ff0000, 0x0000ff00, 0xff, 0x0}; + + SampleModel[] inputSampleModels = { + new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, + 1, 1, 1, 1, bandOffsets), + new PixelInterleavedSampleModel(DataBuffer.TYPE_USHORT, + 1, 1, 1, 1, bandOffsets), + new PixelInterleavedSampleModel(DataBuffer.TYPE_INT, + 1, 1, 1, 1, bandOffsets), + new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, bitMask), + new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT, + width, height, bitMask), + new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, + width, height, bitMask), + new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 4), + new MultiPixelPackedSampleModel(DataBuffer.TYPE_USHORT, + width, height, 2), + new MultiPixelPackedSampleModel(DataBuffer.TYPE_INT, + width, height, 2) + }; + + // --------------------------------------------------------------------- + // Test ability to create Raster & WritableRaster with DataBuffer + // classes + // --------------------------------------------------------------------- + DataBuffer[] inputDataBuffer = { + new DataBufferByte(imageSize), + new DataBufferUShort(imageSize), + new DataBufferInt(imageSize, 1), + new DataBufferShort(imageSize), + new DataBufferFloat(imageSize), + new DataBufferDouble(imageSize) + }; + + for (SampleModel sm : inputSampleModels) { + for (DataBuffer db : inputDataBuffer) { + // Test Raster creation + Raster.createRaster(sm, db, location); + + // Test writableRaster creation + Raster.createWritableRaster(sm, db, location); + Raster.createWritableRaster(sm, location); + } + } + + // --------------------------------------------------------------------- + // Test ability to create Raster & WritableRaster with custom DataBuffer + // classes + // --------------------------------------------------------------------- + DataBuffer[] myDataBuffer = { + new MyDataBufferByte(imageSize), + new MyDataBufferUShort(imageSize), + new MyDataBufferInt(imageSize), + new MyDataBufferShort(imageSize), + new MyDataBufferDouble(imageSize), + new MyDataBufferFloat(imageSize) + }; + + for (SampleModel sm : inputSampleModels) { + for (DataBuffer db : myDataBuffer) { + // Test Raster creation + Raster.createRaster(sm, db, location); + + // Test writableRaster creation + Raster.createWritableRaster(sm, db, location); + Raster.createWritableRaster(sm, location); + } + } + + // --------------------------------------------------------------------- + // Test ability to create InterleavedRaster + // --------------------------------------------------------------------- + int[] interleavedInputDataTypes = { + DataBuffer.TYPE_BYTE, + DataBuffer.TYPE_USHORT + }; + + int numBands = 1; + + for (int i : interleavedInputDataTypes) { + Raster.createInterleavedRaster(i, width, height, 1, location); + Raster.createInterleavedRaster(i, width, height, width * numBands, + numBands, bandOffsets, location); + } + + for (int i = 0; i < interleavedInputDataTypes.length ; i++) { + DataBuffer d1 = inputDataBuffer[i]; + DataBuffer d2 = myDataBuffer[i]; + + Raster.createInterleavedRaster(d1, width, height, width * numBands, + numBands, bandOffsets, location); + Raster.createInterleavedRaster(d2, width, height, width * numBands, + numBands, bandOffsets, location); + } + + // --------------------------------------------------------------------- + // Test ability to create BandedRaster + // --------------------------------------------------------------------- + int[] bankIndices = new int[numBands]; + bankIndices[0] = 0; + + int[] bandedInputDataTypes = { + DataBuffer.TYPE_BYTE, + DataBuffer.TYPE_USHORT, + DataBuffer.TYPE_INT + }; + + for (int i : bandedInputDataTypes) { + Raster.createBandedRaster(i, width, height, 1, location); + Raster.createBandedRaster(i, width, height, width, + bankIndices, bandOffsets, location); + } + + for (int i = 0; i < bandedInputDataTypes.length; i++) { + DataBuffer d1 = inputDataBuffer[i]; + DataBuffer d2 = myDataBuffer[i]; + + Raster.createBandedRaster(d1, width, height, width, + bankIndices, bandOffsets, location); + Raster.createBandedRaster(d2, width, height, width, + bankIndices, bandOffsets, location); + } + + // --------------------------------------------------------------------- + // Test ability to create PackedRaster + // --------------------------------------------------------------------- + int[] bandMasks = new int[numBands]; + bandMasks[0] = 0; + + int packedInputDataTypes[] = { + DataBuffer.TYPE_BYTE, + DataBuffer.TYPE_USHORT, + DataBuffer.TYPE_INT + }; + + for (int i : packedInputDataTypes) { + Raster.createPackedRaster(i, width, height, bandMasks, location); + + for (int bits = 1; bits < 5; bits *= 2) { + Raster.createPackedRaster(i, width, height, 1, bits, location); + } + } + + for (int i = 0; i < packedInputDataTypes.length; i++) { + DataBuffer d1 = inputDataBuffer[i]; + DataBuffer d2 = myDataBuffer[i]; + + for (int bits = 1; bits < 5; bits *= 2) { + Raster.createPackedRaster(d1, width, height, bits, location); + Raster.createPackedRaster(d2, width, height, bits, location); + } + + Raster.createPackedRaster(d1, width, height, 1,bandMasks, location); + Raster.createPackedRaster(d2, width, height, 1,bandMasks, location); + } + } +} + +// --------------------------------------------------------------------- +// Custom DataBuffer classes for testing purpose +// --------------------------------------------------------------------- +final class MyDataBufferByte extends DataBuffer { + + byte[] data; + byte[][] bankdata; + + public MyDataBufferByte(int size) { + super(TYPE_BYTE, size); + data = new byte[size]; + bankdata = new byte[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (byte) val; + } +} + +final class MyDataBufferDouble extends DataBuffer { + + double[] data; + double[][] bankdata; + + public MyDataBufferDouble(int size) { + super(TYPE_DOUBLE, size); + data = new double[size]; + bankdata = new double[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return (int) bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (double) val; + } +} + +final class MyDataBufferFloat extends DataBuffer { + + float[] data; + float[][] bankdata; + + public MyDataBufferFloat(int size) { + super(TYPE_FLOAT, size); + data = new float[size]; + bankdata = new float[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return (int) bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (float) val; + } +} + +final class MyDataBufferShort extends DataBuffer { + + short[] data; + short[][] bankdata; + + public MyDataBufferShort(int size) { + super(TYPE_SHORT, size); + data = new short[size]; + bankdata = new short[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (short) val; + } +} + +final class MyDataBufferUShort extends DataBuffer { + + short[] data; + short[][] bankdata; + + public MyDataBufferUShort(int size) { + super(TYPE_USHORT, size); + data = new short[size]; + bankdata = new short[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (short) val; + } +} + +final class MyDataBufferInt extends DataBuffer { + + int[] data; + int[][] bankdata; + + public MyDataBufferInt(int size) { + super(TYPE_INT, size); + data = new int[size]; + bankdata = new int[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (int) val; + } +} From a7b8a6a5ccf2839052fb14cd777f9ecf071066e6 Mon Sep 17 00:00:00 2001 From: Dmitry Markov Date: Fri, 1 Apr 2016 11:22:22 +0300 Subject: [PATCH 039/222] 8073400: Some Monospaced logical fonts have a different width Reviewed-by: okutsu, prr --- .../fontconfig/windows.fontconfig.properties | 2 +- .../MonospacedGlyphWidthTest.java | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/awt/font/MonospacedGlyphWidth/MonospacedGlyphWidthTest.java diff --git a/jdk/make/data/fontconfig/windows.fontconfig.properties b/jdk/make/data/fontconfig/windows.fontconfig.properties index 9d3fa4a8315..3a2e2b31b18 100644 --- a/jdk/make/data/fontconfig/windows.fontconfig.properties +++ b/jdk/make/data/fontconfig/windows.fontconfig.properties @@ -243,7 +243,7 @@ sequence.fallback=lucida,symbols,\ # Exclusion Ranges -exclusion.alphabetic=0700-1e9f,1f00-20ab,20ad-f8ff +exclusion.alphabetic=0700-1e9f,1f00-2017,2020-20ab,20ad-f8ff exclusion.chinese-gb18030=0390-03d6,2200-22ef,2701-27be exclusion.hebrew=0041-005a,0060-007a,007f-00ff,20ac-20ac diff --git a/jdk/test/java/awt/font/MonospacedGlyphWidth/MonospacedGlyphWidthTest.java b/jdk/test/java/awt/font/MonospacedGlyphWidth/MonospacedGlyphWidthTest.java new file mode 100644 index 00000000000..82dd8ab57f1 --- /dev/null +++ b/jdk/test/java/awt/font/MonospacedGlyphWidth/MonospacedGlyphWidthTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8073400 + * @summary Some Monospaced logical fonts have a different width + * @author Dmitry Markov + * @run main MonospacedGlyphWidthTest + */ +import java.awt.*; +import java.awt.font.FontRenderContext; + +public class MonospacedGlyphWidthTest { + private static final int START_INDEX = 0x2018; + private static final int END_INDEX = 0x201F; + + public static void main(String[] args) { + Font font = new Font(Font.MONOSPACED, Font.PLAIN, 12); + double width = getCharWidth(font, 'a'); + + for (int i = START_INDEX; i <= END_INDEX; i++) { + if (width != getCharWidth(font, (char)i)) { + throw new RuntimeException("Test Failed: characters have different width!"); + } + } + System.out.println("Test Passed!"); + } + + private static double getCharWidth(Font font, char c) { + FontRenderContext fontRenderContext = new FontRenderContext(null, false, false); + return font.getStringBounds(new char[] {c}, 0, 1, fontRenderContext).getWidth(); + } +} + From fbd868d77c3a0ee11613071e976366f6395e192e Mon Sep 17 00:00:00 2001 From: Alexander Stepanov Date: Fri, 1 Apr 2016 13:52:04 +0300 Subject: [PATCH 040/222] 8149028: [TEST] add test for TIFFDirectory Reviewed-by: ssadetsky, yan --- .../plugins/tiff/TIFFDirectoryTest.java | 266 +++++++++++++++++ .../tiff/TIFFDirectoryWriteReadTest.java | 255 ++++++++++++++++ .../plugins/tiff/TIFFImageReadParamTest.java | 275 ++++++++++++++++++ 3 files changed, 796 insertions(+) create mode 100644 jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java create mode 100644 jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java create mode 100644 jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java new file mode 100644 index 00000000000..39c2474512c --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8149028 + * @author a.stepanov + * @summary some simple checks for TIFFDirectory + * @run main TIFFDirectoryTest + */ + +import java.util.List; +import java.util.ArrayList; +import javax.imageio.metadata.*; +import javax.imageio.plugins.tiff.*; + + +public class TIFFDirectoryTest { + + private static void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + private void run() { + + int type = TIFFTag.TIFF_LONG, dt = 1 << type; + int n0 = 1000, n1 = 1001, n2 = 1002, n3 = 1003; + + TIFFTag tag1 = new TIFFTag(Integer.toString(n1), n1, dt); + TIFFTag tag2 = new TIFFTag(Integer.toString(n2), n2, dt); + TIFFTag tag3 = new TIFFTag(Integer.toString(n3), n3, dt); + TIFFTag parent = new TIFFTag(Integer.toString(n0), n0, dt); + + // tag sets array must not be null + boolean ok = false; + try { new TIFFDirectory(null, parent); } + catch (NullPointerException e) { ok = true; } + check(ok, "can construct TIFFDirectory with null tagsets array"); + + // but can be empty + TIFFTagSet emptySets[] = {}; + TIFFDirectory d = new TIFFDirectory(emptySets, parent); + check(d.getTagSets().length == 0, "invalid number of tag sets"); + check(d.getParentTag().getName().equals(Integer.toString(n0)) && + (d.getParentTag().getNumber() == n0), "invalid parent tag"); + + + // add tags + List tags = new ArrayList<>(); + tags.add(tag1); + tags.add(tag2); + TIFFTagSet ts1 = new TIFFTagSet(tags); + + tags.clear(); + tags.add(tag3); + TIFFTagSet ts2 = new TIFFTagSet(tags); + + TIFFTagSet sets[] = {ts1, ts2}; + d = new TIFFDirectory(sets, parent); + + check(d.getTagSets().length == sets.length, "invalid number of tag sets"); + + // check getTag() + for (int i = n1; i <= n3; i++) { + TIFFTag t = d.getTag(i); + check(t.getNumber() == i, "invalid tag number"); + check(t.getName().equals(Integer.toString(i)), "invalid tag name"); + check(t.getDataTypes() == dt, "invalid tag data types"); + } + + TIFFDirectory d2; + try { d2 = d.clone(); } + catch (CloneNotSupportedException e) { throw new RuntimeException(e); } + + // check removeTagSet() + d.removeTagSet(ts2); + check(d.getTagSets().length == 1, "invalid number of tag sets"); + check(d.getTagSets()[0].getTag(n1).getName().equals(Integer.toString(n1)), + "invalid tag name"); + check(d.getTagSets()[0].getTag(n2).getName().equals(Integer.toString(n2)), + "invalid tag name"); + + d.removeTagSet(ts1); + check(d.getTagSets().length == 0, "invalid number of tag sets"); + + // check cloned data + check(d2.getTagSets().length == sets.length, + "invalid number of tag sets"); + TIFFTagSet sets2[] = d2.getTagSets(); + check(sets2.length == sets.length, "invalid number of tag sets"); + check( + (sets2[0].getTag(Integer.toString(n1)).getNumber() == n1) && + (sets2[0].getTag(Integer.toString(n2)).getNumber() == n2) && + (sets2[0].getTag(Integer.toString(n0)) == null) && + (sets2[1].getTag(Integer.toString(n3)).getNumber() == n3) && + (sets2[1].getTag(Integer.toString(n0)) == null), "invalid data"); + + check( + (sets2[0].getTag(Integer.toString(n1)).getDataTypes() == dt) && + (sets2[0].getTag(Integer.toString(n2)).getDataTypes() == dt) && + (sets2[1].getTag(Integer.toString(n3)).getDataTypes() == dt), + "invalid data type"); + + // must not be able to call removeTagSet with null argument + ok = false; + try { d.removeTagSet(null); } + catch (NullPointerException e) { ok = true; } + check(ok, "must not be able to use null as an argument for remove"); + + // check parent tag + check( d.getParentTag().getName().equals(Integer.toString(n0)) && + d2.getParentTag().getName().equals(Integer.toString(n0)), + "invalid parent tag name"); + + check(( d.getParentTag().getNumber() == n0) && + (d2.getParentTag().getNumber() == n0), + "invalid parent tag number"); + + check(( d.getParentTag().getDataTypes() == dt) && + (d2.getParentTag().getDataTypes() == dt), + "invalid parent data type"); + + d.addTagSet(ts1); + d.addTagSet(ts2); + + // add the same tag set twice and check that nothing changed + d.addTagSet(ts2); + + check(d.getTagSets().length == 2, "invalid number of tag sets"); + + // check field operations + check(d.getNumTIFFFields() == 0, "invalid TIFFFields number"); + check(d.getTIFFField(Integer.MAX_VALUE) == null, + "must return null TIFFField"); + + long offset = 4L; + long a[] = {Long.MIN_VALUE, 0, Long.MAX_VALUE}; + int v = 100500; + TIFFField + f1 = new TIFFField(tag1, type, offset, d), + f2 = new TIFFField(tag2, v), + f3 = new TIFFField(tag3, type, a.length, a); + + d.addTIFFField(f1); + d.addTIFFField(f2); + d.addTIFFField(f3); + + check(d.containsTIFFField(n1) && + d.containsTIFFField(n2) && + d.containsTIFFField(n3) && + !d.containsTIFFField(n0), "invalid containsTIFFField() results"); + + check(d.getTIFFField(n0) == null, "can get unadded field"); + + check(d.getNumTIFFFields() == 3, "invalid TIFFFields number"); + + check(d.getTIFFField(n1).getCount() == 1, "invalid TIFFField count"); + check(d.getTIFFField(n1).getAsLong(0) == offset, "invalid offset"); + + check(d.getTIFFField(n2).getCount() == 1, "invalid TIFFField count"); + check(d.getTIFFField(n2).getAsInt(0) == v, "invalid TIFFField value"); + + check(d.getTIFFField(n3).getCount() == a.length, + "invalid TIFFField count"); + for (int i = 0; i < a.length; ++i) { + check(d.getTIFFField(n3).getAsLong(i) == a[i], + "invalid TIFFField value"); + } + + TIFFField nested = d.getTIFFField(n1).getDirectory().getTIFFField(n1); + check(nested.getTag().getNumber() == n1, "invalid tag number"); + check(nested.getCount() == 1, "invalid field count"); + check(nested.getAsLong(0) == offset, "invalid offset"); + + // check that the field is overwritten correctly + int v2 = 1 << 16; + d.addTIFFField(new TIFFField(tag3, v2)); + check(d.getTIFFField(n3).getCount() == 1, "invalid TIFFField count"); + check(d.getTIFFField(n3).getAsInt(0)== v2, "invalid TIFFField value"); + check(d.getNumTIFFFields() == 3, "invalid TIFFFields number"); + + // check removeTIFFField() + d.removeTIFFField(n3); + check(d.getNumTIFFFields() == 2, "invalid TIFFFields number"); + check(d.getTIFFField(n3) == null, "can get removed field"); + + d.removeTIFFFields(); + check((d.getTIFFField(n1) == null) && (d.getTIFFField(n2) == null), + "can get removed field"); + check((d.getNumTIFFFields() == 0) && (d.getTIFFFields().length == 0), + "invalid TIFFFields number"); + + // check that array returned by getTIFFFields() is sorted + // by tag number (as it stated in the docs) + d.addTIFFField(f3); + d.addTIFFField(f1); + d.addTIFFField(f2); + + TIFFField fa[] = d.getTIFFFields(); + check(fa.length == 3, "invalid number of fields"); + check((fa[0].getTagNumber() == n1) && + (fa[1].getTagNumber() == n2) && + (fa[2].getTagNumber() == n3), + "array of the fields must be sorted by tag number"); + + d.removeTIFFFields(); + d.addTIFFField(f2); + + // test getAsMetaData / createFromMetadata + try { + d2 = TIFFDirectory.createFromMetadata(d.getAsMetadata()); + } catch (IIOInvalidTreeException e) { + throw new RuntimeException(e); + } + + // check new data + check(d2.getTagSets().length == sets.length, + "invalid number of tag sets"); + sets2 = d2.getTagSets(); + check(sets2.length == sets.length, "invalid number of tag sets"); + check( + (sets2[0].getTag(Integer.toString(n1)).getNumber() == n1) && + (sets2[0].getTag(Integer.toString(n2)).getNumber() == n2) && + (sets2[0].getTag(Integer.toString(n0)) == null) && + (sets2[1].getTag(Integer.toString(n3)).getNumber() == n3) && + (sets2[1].getTag(Integer.toString(n0)) == null), "invalid data"); + + check( + (sets2[0].getTag(Integer.toString(n1)).getDataTypes() == dt) && + (sets2[0].getTag(Integer.toString(n2)).getDataTypes() == dt) && + (sets2[1].getTag(Integer.toString(n3)).getDataTypes() == dt), + "invalid data type"); + + check(!d2.containsTIFFField(n1) && + d2.containsTIFFField(n2) && + !d2.containsTIFFField(n3), "invalid containsTIFFField() results"); + check(d2.getTIFFField(n2).getCount() == 1, "invalid TIFFField count"); + check(d2.getTIFFField(n2).getAsInt(0) == v, "invalid TIFFField value"); + + check((d2.getParentTag().getNumber() == n0) && + d2.getParentTag().getName().equals(Integer.toString(n0)), + "invalid parent tag"); + } + + public static void main(String[] args) { (new TIFFDirectoryTest()).run(); } +} diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java new file mode 100644 index 00000000000..eb668255ea6 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8149028 + * @author a.stepanov + * @summary a simple write-read test for TIFFDirectory + * @run main TIFFDirectoryWriteReadTest + */ + +import java.awt.*; +import java.awt.color.*; +import java.awt.image.BufferedImage; +import java.io.*; +import javax.imageio.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.*; +import javax.imageio.plugins.tiff.*; + + +public class TIFFDirectoryWriteReadTest { + + private final static String FILENAME = "test.tiff"; + private final static int SZ = 100; + private final static Color C = Color.RED; + + private static final String COPYRIGHT[] = {"Copyright 123ABC.."}; + private static final String DESCRIPTION[] = {"Test Image", "Description"}; + private static final String SOFTWARE[] = {"test", "software", "123"}; + + private static final long RES_X[][] = {{2, 1}}, RES_Y[][] = {{1, 1}}; + + private static final byte[] ICC_PROFILE = + ICC_ProfileRGB.getInstance(ColorSpace.CS_sRGB).getData(); + + + private ImageWriter getTIFFWriter() { + + java.util.Iterator writers = + ImageIO.getImageWritersByFormatName("TIFF"); + if (!writers.hasNext()) { + throw new RuntimeException("No writers available for TIFF format"); + } + return writers.next(); + } + + private ImageReader getTIFFReader() { + + java.util.Iterator readers = + ImageIO.getImageReadersByFormatName("TIFF"); + if (!readers.hasNext()) { + throw new RuntimeException("No readers available for TIFF format"); + } + return readers.next(); + } + + private void addASCIIField(TIFFDirectory d, + String name, + String data[], + int num) { + + d.addTIFFField(new TIFFField( + new TIFFTag(name, num, 1 << TIFFTag.TIFF_ASCII), + TIFFTag.TIFF_ASCII, data.length, data)); + } + + private void checkASCIIField(TIFFDirectory d, + String what, + String data[], + int num) { + + String notFound = what + " field was not found"; + check(d.containsTIFFField(num), notFound); + TIFFField f = d.getTIFFField(num); + check(f.getType() == TIFFTag.TIFF_ASCII, "field type != ASCII"); + check(f.getCount() == data.length, "invalid " + what + " data count"); + for (int i = 0; i < data.length; i++) { + check(f.getValueAsString(i).equals(data[i]), + "invalid " + what + " data"); + } + } + + private void writeImage() throws Exception { + + OutputStream s = new BufferedOutputStream(new FileOutputStream(FILENAME)); + try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) { + + ImageWriter writer = getTIFFWriter(); + writer.setOutput(ios); + + BufferedImage img = new BufferedImage( + SZ, SZ, BufferedImage.TYPE_INT_RGB); + Graphics g = img.getGraphics(); + g.setColor(C); + g.fillRect(0, 0, SZ, SZ); + g.dispose(); + + IIOMetadata metadata = writer.getDefaultImageMetadata( + new ImageTypeSpecifier(img), writer.getDefaultWriteParam()); + + TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata); + + addASCIIField(dir, "Copyright", + COPYRIGHT, BaselineTIFFTagSet.TAG_COPYRIGHT); + + addASCIIField(dir, "ImageDescription", + DESCRIPTION, BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION); + + addASCIIField(dir, "Software", + SOFTWARE, BaselineTIFFTagSet.TAG_SOFTWARE); + + dir.addTIFFField(new TIFFField( + new TIFFTag("XResolution", BaselineTIFFTagSet.TAG_X_RESOLUTION, + 1 << TIFFTag.TIFF_RATIONAL), TIFFTag.TIFF_RATIONAL, 1, RES_X)); + dir.addTIFFField(new TIFFField( + new TIFFTag("YResolution", BaselineTIFFTagSet.TAG_Y_RESOLUTION, + 1 << TIFFTag.TIFF_RATIONAL), TIFFTag.TIFF_RATIONAL, 1, RES_Y)); + + dir.addTIFFField(new TIFFField( + new TIFFTag("ICC Profile", BaselineTIFFTagSet.TAG_ICC_PROFILE, + 1 << TIFFTag.TIFF_UNDEFINED), + TIFFTag.TIFF_UNDEFINED, ICC_PROFILE.length, ICC_PROFILE)); + + IIOMetadata data = dir.getAsMetadata(); + writer.write(new IIOImage(img, null, data)); + + ios.flush(); + writer.dispose(); + } + s.close(); + } + + + + private void readAndCheckImage() throws Exception { + + ImageReader reader = getTIFFReader(); + + ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME)); + reader.setInput(s); + + int ni = reader.getNumImages(true); + check(ni == 1, "invalid number of images"); + + // check image + BufferedImage img = reader.read(0); + check(img.getWidth() == SZ && img.getHeight() == SZ, + "invalid image size"); + + Color c = new Color(img.getRGB(SZ / 2, SZ / 2)); + check(C.equals(c), "invalid image color"); + + IIOMetadata metadata = reader.readAll(0, null).getMetadata(); + TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata); + + reader.dispose(); + s.close(); + + // ===== perform tag checks ===== + + checkASCIIField(dir, "copyright", COPYRIGHT, + BaselineTIFFTagSet.TAG_COPYRIGHT); + + checkASCIIField(dir, "description", DESCRIPTION, + BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION); + + checkASCIIField(dir, "software", SOFTWARE, + BaselineTIFFTagSet.TAG_SOFTWARE); + + TIFFField f = dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH); + check(f.getCount() == 1, "invalid width field count"); + int w = f.getAsInt(0); + check(w == SZ, "invalid width"); + + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_LENGTH); + check(f.getCount() == 1, "invalid height field count"); + int h = f.getAsInt(0); + check(h == SZ, "invalid height"); + + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); + // RGB: 3 x 8 bits for R, G and B components + int bps[] = f.getAsInts(); + check((f.getCount() == 3) && (bps.length == 3), "invalid BPS count"); + for (int b: bps) { check(b == 8, "invalid bits per sample"); } + + // RGB: PhotometricInterpretation = 2 + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); + check(f.getCount() == 1, "invalid count"); + check(f.getAsInt(0) == 2, "invalid photometric interpretation for RGB"); + + String rat = " resolution must be rational"; + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION); + check(f.getType() == TIFFTag.TIFF_RATIONAL, "x" + rat); + check(f.getCount() == 1 && + f.getAsInt(0) == (int) (RES_X[0][0] / RES_X[0][1]), + "invalid x resolution"); + + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_Y_RESOLUTION); + check(f.getType() == TIFFTag.TIFF_RATIONAL, "y" + rat); + check(f.getCount() == 1 && + f.getAsInt(0) == (int) (RES_Y[0][0] / RES_Y[0][1]), + "invalid y resolution"); + + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_ICC_PROFILE); + check(f.getType() == TIFFTag.TIFF_UNDEFINED, + "invalid ICC profile field type"); + int cnt = f.getCount(); + byte icc[] = f.getAsBytes(); + check((cnt == ICC_PROFILE.length) && (cnt == icc.length), + "invalid ICC profile"); + for (int i = 0; i < cnt; i++) { + check(icc[i] == ICC_PROFILE[i], "invalid ICC profile"); + } + } + + public void run() { + + try { + writeImage(); + readAndCheckImage(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + private void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + public static void main(String[] args) { + (new TIFFDirectoryWriteReadTest()).run(); + } +} diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java new file mode 100644 index 00000000000..34fd5ed8983 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8149028 + * @author a.stepanov + * @summary check TIFFDirectory manipulation + * by means of TIFFImageReadParam + * @run main TIFFImageReadParamTest + */ + + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.*; +import javax.imageio.*; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.plugins.tiff.*; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; + +public class TIFFImageReadParamTest { + + private final static String FILENAME = "test.tiff"; + private final static int SZ = 100; + private final static Color C = Color.RED; + + private final static String GEO_DATA = "test params"; + private final static int GEO_N = GeoTIFFTagSet.TAG_GEO_ASCII_PARAMS; + + private final static String EXIF_DATA = "2000:01:01 00:00:01"; + private final static int EXIF_N = ExifTIFFTagSet.TAG_DATE_TIME_ORIGINAL; + + private final static String GPS_DATA = + ExifGPSTagSet.STATUS_MEASUREMENT_IN_PROGRESS; + private final static int GPS_N = ExifGPSTagSet.TAG_GPS_STATUS; + + private final static short FAX_DATA = + FaxTIFFTagSet.CLEAN_FAX_DATA_ERRORS_UNCORRECTED; + private final static int FAX_N = FaxTIFFTagSet.TAG_CLEAN_FAX_DATA; + + private ImageWriter getTIFFWriter() { + + java.util.Iterator writers = + ImageIO.getImageWritersByFormatName("TIFF"); + if (!writers.hasNext()) { + throw new RuntimeException("No writers available for TIFF format"); + } + return writers.next(); + } + + private ImageReader getTIFFReader() { + + java.util.Iterator readers = + ImageIO.getImageReadersByFormatName("TIFF"); + if (!readers.hasNext()) { + throw new RuntimeException("No readers available for TIFF format"); + } + return readers.next(); + } + + private void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + private void addASCIIField(TIFFDirectory d, + String name, + String data, + int num) { + + String a[] = {data}; + d.addTIFFField(new TIFFField( + new TIFFTag(name, num, 1 << TIFFTag.TIFF_ASCII), + TIFFTag.TIFF_ASCII, 1, a)); + } + + private void checkASCIIValue(TIFFDirectory d, + String what, + String data, + int num) { + + TIFFField f = d.getTIFFField(num); + check(f.getType() == TIFFTag.TIFF_ASCII, "field type != ASCII"); + check(f.getCount() == 1, "invalid " + what + " data count"); + check(f.getValueAsString(0).equals(data), + "invalid " + what + " data"); + } + + + private void writeImage() throws Exception { + + OutputStream s = new BufferedOutputStream(new FileOutputStream(FILENAME)); + try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) { + ImageWriter writer = getTIFFWriter(); + writer.setOutput(ios); + + BufferedImage img = + new BufferedImage(SZ, SZ, BufferedImage.TYPE_INT_RGB); + Graphics g = img.getGraphics(); + g.setColor(C); + g.fillRect(0, 0, SZ, SZ); + g.dispose(); + + IIOMetadata metadata = writer.getDefaultImageMetadata( + new ImageTypeSpecifier(img), writer.getDefaultWriteParam()); + + TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata); + + // add some extension tags + addASCIIField(dir, "GeoAsciiParamsTag", GEO_DATA, GEO_N); + addASCIIField(dir, "DateTimeOriginal", EXIF_DATA, EXIF_N); + addASCIIField(dir, "GPSStatus", GPS_DATA, GPS_N); + + dir.addTIFFField(new TIFFField(new TIFFTag( + "CleanFaxData", FAX_N, 1 << TIFFTag.TIFF_SHORT), FAX_DATA)); + + IIOMetadata data = dir.getAsMetadata(); + + writer.write(new IIOImage(img, null, data)); + + ios.flush(); + writer.dispose(); + } + } + + private void checkImage(BufferedImage img) { + + check(img.getWidth() == SZ, "invalid image width"); + check(img.getHeight() == SZ, "invalid image height"); + Color c = new Color(img.getRGB(SZ / 2, SZ / 2)); + check(c.equals(C), "invalid image color"); + } + + private TIFFDirectory getDir(TIFFTagSet[] add, + TIFFTagSet[] remove) throws Exception { + + ImageReader reader = getTIFFReader(); + + ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME)); + reader.setInput(s, false, true); + + int ni = reader.getNumImages(true); + check(ni == 1, "invalid number of images: " + ni); + + TIFFImageReadParam param = new TIFFImageReadParam(); + for (TIFFTagSet ts: add) { param.addAllowedTagSet(ts); } + for (TIFFTagSet ts: remove) { param.removeAllowedTagSet(ts); } + + IIOImage img = reader.readAll(0, param); + + // just in case, check image + checkImage((BufferedImage) img.getRenderedImage()); + + IIOMetadata metadata = img.getMetadata(); + TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata); + + reader.dispose(); + s.close(); + + return dir; + } + + private void simpleChecks() { + + TIFFImageReadParam param = new TIFFImageReadParam(); + + java.util.List allowed = param.getAllowedTagSets(); + + // see docs + check(allowed.contains(BaselineTIFFTagSet.getInstance()), + "must contain BaselineTIFFTagSet"); + check(allowed.contains(FaxTIFFTagSet.getInstance()), + "must contain FaxTIFFTagSet"); + check(allowed.contains(ExifParentTIFFTagSet.getInstance()), + "must contain ExifParentTIFFTagSet"); + check(allowed.contains(GeoTIFFTagSet.getInstance()), + "must contain GeoTIFFTagSet"); + + TIFFTagSet gps = ExifGPSTagSet.getInstance(); + param.addAllowedTagSet(gps); + check(param.getAllowedTagSets().contains(gps), + "must contain ExifGPSTagSet"); + + param.removeAllowedTagSet(gps); + check(!param.getAllowedTagSets().contains(gps), + "must not contain ExifGPSTagSet"); + + // check that repeating remove goes properly + param.removeAllowedTagSet(gps); + + boolean ok = false; + try { param.addAllowedTagSet(null); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "must not be able to add null tag set"); + + ok = false; + try { param.removeAllowedTagSet(null); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "must not be able to remove null tag set"); + } + + private void run() { + + simpleChecks(); + + try { + + writeImage(); + + TIFFTagSet + empty[] = {}, + geo[] = { GeoTIFFTagSet.getInstance() }, + exif[] = { ExifTIFFTagSet.getInstance() }, + gps[] = { ExifGPSTagSet.getInstance() }, + fax[] = { FaxTIFFTagSet.getInstance() }; + + // default param state + TIFFDirectory dir = getDir(empty, empty); + // Geo and Fax are default allowed tag sets + check(dir.containsTIFFField(GEO_N), "must contain Geo field"); + checkASCIIValue(dir, "Geo", GEO_DATA, GEO_N); + check(dir.containsTIFFField(FAX_N), "must contain Fax field"); + check( + (dir.getTIFFField(FAX_N).getCount() == 1) && + (dir.getTIFFField(FAX_N).getAsInt(0) == FAX_DATA), + "invalid Fax field value"); + + // corresponding tag sets are non-default + check(!dir.containsTIFFField(EXIF_N), "must not contain Geo field"); + check(!dir.containsTIFFField(GPS_N), "must not contain GPS field"); + + // remove Fax + dir = getDir(empty, fax); + check(!dir.containsTIFFField(FAX_N), "must not contain Fax field"); + + // add EXIF, remove Geo + dir = getDir(exif, geo); + check(dir.containsTIFFField(EXIF_N), "must contain EXIF field"); + checkASCIIValue(dir, "EXIF", EXIF_DATA, EXIF_N); + check(!dir.containsTIFFField(GEO_N), "must not contain Geo field"); + + // add GPS + dir = getDir(gps, empty); + check(dir.containsTIFFField(GPS_N), "must contain GPS field"); + checkASCIIValue(dir, "GPS", GPS_DATA, GPS_N); + + } catch (Exception e) { throw new RuntimeException(e); } + } + + public static void main(String[] args) { + (new TIFFImageReadParamTest()).run(); + } +} From 8bc85384cdc789835040d270d37d503c3d2c0ef8 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 1 Apr 2016 09:52:13 -0700 Subject: [PATCH 041/222] 8153272: [pit] Tag @run requires "main" in java/awt/FontClass/CreateFont/CreateFontArrayTest.java Reviewed-by: yan --- .../java/awt/FontClass/CreateFont/CreateFontArrayTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/test/java/awt/FontClass/CreateFont/CreateFontArrayTest.java b/jdk/test/java/awt/FontClass/CreateFont/CreateFontArrayTest.java index d68b2e4409f..4dbff501d39 100644 --- a/jdk/test/java/awt/FontClass/CreateFont/CreateFontArrayTest.java +++ b/jdk/test/java/awt/FontClass/CreateFont/CreateFontArrayTest.java @@ -23,9 +23,9 @@ /* * @test - * @bug 8055463 + * @bug 8055463 8153272 * @summary Test createFont APIs - * @run CreateFontArrayTest + * @run main CreateFontArrayTest */ import java.awt.Font; From dc61e8176dc402e22fa51004003fa3625bcfe21d Mon Sep 17 00:00:00 2001 From: Prem Balakrishnan Date: Mon, 4 Apr 2016 11:26:14 +0530 Subject: [PATCH 042/222] 6897701: In Nimbus Disabled Menus and Menu Items don't look disabled Reviewed-by: ssadetsky, alexsch --- .../javax/swing/plaf/synth/SynthStyle.java | 2 +- .../LookAndFeel/6897701/JMenuItemsTest.java | 130 ++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/swing/LookAndFeel/6897701/JMenuItemsTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java index bf41d10dff1..56744c2a03b 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java @@ -775,7 +775,7 @@ public abstract class SynthStyle { if (disabledColor == null || disabledColor instanceof UIResource) { return getColorForState(context, type); } - } else if (c instanceof JLabel && + } else if ((c instanceof JLabel || c instanceof JMenuItem) && (type == ColorType.FOREGROUND || type == ColorType.TEXT_FOREGROUND)) { return getColorForState(context, type); diff --git a/jdk/test/javax/swing/LookAndFeel/6897701/JMenuItemsTest.java b/jdk/test/javax/swing/LookAndFeel/6897701/JMenuItemsTest.java new file mode 100644 index 00000000000..c8e2492de2f --- /dev/null +++ b/jdk/test/javax/swing/LookAndFeel/6897701/JMenuItemsTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6897701 + * @summary Verify JMenu and JMenuItem Disabled state for Nimbus LAF + * @run main JMenuItemsTest + */ +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class JMenuItemsTest { + + private static JFrame mainFrame; + private static JMenu disabledMenu; + private static JMenuItem disabledMenuItem; + + public JMenuItemsTest() { + createUI(); + } + + private void createUI() { + + mainFrame = new JFrame("Test"); + + disabledMenu = new JMenu("Disabled Menu"); + disabledMenu.setForeground(Color.BLUE); + disabledMenu.setEnabled(false); + + disabledMenuItem = new JMenuItem("Disabled MenuItem"); + disabledMenuItem.setForeground(Color.BLUE); + disabledMenuItem.setEnabled(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar = new JMenuBar(); + menuBar.add(disabledMenu); + menuBar.add(disabledMenuItem); + + mainFrame.add(menuBar); + mainFrame.pack(); + mainFrame.setVisible(true); + } + + private void dispose() { + mainFrame.dispose(); + } + + private void testDisabledStateOfJMenu() { + + // Test disabled JMenu state + Rectangle rect = disabledMenu.getBounds(); + BufferedImage image = new BufferedImage(rect.width, rect.height, + BufferedImage.TYPE_INT_ARGB); + disabledMenu.paint(image.getGraphics()); + int y = image.getHeight() / 2; + for (int x = 0; x < image.getWidth(); x++) { + Color c = new Color(image.getRGB(x, y)); + if (c.equals(Color.BLUE)) { + dispose(); + throw new RuntimeException("JMenu Disabled" + + " State not Valid."); + } + } + + } + + private void testDisabledStateOfJMenuItem() { + + // Test disabled JMenuItem state + Rectangle rect = disabledMenuItem.getBounds(); + BufferedImage image = new BufferedImage(rect.width, rect.height, + BufferedImage.TYPE_INT_ARGB); + disabledMenuItem.paint(image.getGraphics()); + int y = image.getHeight() / 2; + for (int x = 0; x < image.getWidth(); x++) { + Color c = new Color(image.getRGB(x, y)); + if (c.equals(Color.BLUE)) { + dispose(); + throw new RuntimeException("JMenuItem Disabled" + + " State not Valid."); + } + } + + } + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + SwingUtilities.invokeAndWait(() -> { + + try { + JMenuItemsTest obj = new JMenuItemsTest(); + obj.testDisabledStateOfJMenu(); + obj.testDisabledStateOfJMenuItem(); + obj.dispose(); + + } catch (Exception ex) { + throw ex; + } + + }); + } +} From ed6f748110fbd5822e8d9174e723dae0cdaaee5b Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 4 Apr 2016 16:54:59 +0530 Subject: [PATCH 043/222] 6357905: java.awt.JobAttributes.getFromPage() and getToPage() always returns "1" Reviewed-by: prr, jdv --- .../share/classes/sun/print/PrintJob2D.java | 24 +++- .../java/awt/PrintJob/JobAttrUpdateTest.java | 126 ++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/awt/PrintJob/JobAttrUpdateTest.java diff --git a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java index 0d3df28921c..a67fb9be7ce 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -483,8 +483,30 @@ public class PrintJob2D extends PrintJob implements Printable, Runnable { pageFormat.setOrientation(PageFormat.LANDSCAPE); } else { pageFormat.setOrientation(PageFormat.PORTRAIT); - } + } + PageRanges pageRangesAttr + = (PageRanges) attributes.get(PageRanges.class); + if (pageRangesAttr != null) { + // Get the PageRanges from print dialog. + int[][] range = pageRangesAttr.getMembers(); + + int prevFromPage = this.jobAttributes.getFromPage(); + int prevToPage = this.jobAttributes.getToPage(); + + int currFromPage = range[0][0]; + int currToPage = range[range.length - 1][1]; + + // if from < to update fromPage first followed by toPage + // else update toPage first followed by fromPage + if (currFromPage < prevToPage) { + this.jobAttributes.setFromPage(currFromPage); + this.jobAttributes.setToPage(currToPage); + } else { + this.jobAttributes.setToPage(currToPage); + this.jobAttributes.setFromPage(currFromPage); + } + } printerJob.setPrintable(this, pageFormat); } diff --git a/jdk/test/java/awt/PrintJob/JobAttrUpdateTest.java b/jdk/test/java/awt/PrintJob/JobAttrUpdateTest.java new file mode 100644 index 00000000000..186b9a6d8ba --- /dev/null +++ b/jdk/test/java/awt/PrintJob/JobAttrUpdateTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6357905 + * @summary JobAttributes.getFromPage() and getToPage() always returns 1 + * @run main/manual JobAttrUpdateTest + */ +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.JobAttributes; +import java.awt.PrintJob; +import java.awt.Toolkit; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + +public class JobAttrUpdateTest { + + private static Thread mainThread; + private static boolean testPassed; + private static boolean testGeneratedInterrupt; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + doTest(JobAttrUpdateTest::printTest); + }); + mainThread = Thread.currentThread(); + try { + Thread.sleep(30000); + } catch (InterruptedException e) { + if (!testPassed && testGeneratedInterrupt) { + throw new RuntimeException("" + + "JobAttributes.getFromPage(),getToPage() not updated correctly"); + } + } + if (!testGeneratedInterrupt) { + throw new RuntimeException("user has not executed the test"); + } + } + + private static void printTest() { + JobAttributes ja = new JobAttributes(); + + Toolkit tk = Toolkit.getDefaultToolkit(); + // ja.setToPage(4); + // ja.setFromPage(3); + // show dialog + PrintJob pjob = tk.getPrintJob(new JFrame(), "test", ja, null); + if (pjob == null) { + return; + } + + + if (ja.getDefaultSelection() == JobAttributes.DefaultSelectionType.RANGE) { + int fromPage = ja.getFromPage(); + int toPage = ja.getToPage(); + if (fromPage != 2 || toPage != 3) { + fail(); + } else { + pass(); + } + } + } + + public static synchronized void pass() { + testPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + public static synchronized void fail() { + testPassed = false; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + private static void doTest(Runnable action) { + String description + = " A print dialog will be shown.\n " + + " Please select Pages within Page-range.\n" + + " and enter From 2 and To 3. Then Select OK."; + + final JDialog dialog = new JDialog(); + dialog.setTitle("JobAttribute Updation Test"); + JTextArea textArea = new JTextArea(description); + textArea.setEditable(false); + final JButton testButton = new JButton("Start Test"); + + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + action.run(); + }); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + dialog.pack(); + dialog.setVisible(true); + } +} From 01b34486fa0e4e8724e6e5f089850c16758fe23b Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 4 Apr 2016 14:22:07 -0700 Subject: [PATCH 044/222] 8147544: Remove sun.misc.ManagedLocalsThread from java.desktop Reviewed-by: serb, chegar --- .../classes/com/apple/laf/AquaFileSystemModel.java | 3 +-- .../macosx/classes/sun/font/CFontManager.java | 1 - .../macosx/classes/sun/lwawt/LWToolkit.java | 10 +++++----- .../sun/lwawt/macosx/CDragSourceContextPeer.java | 3 +-- .../classes/sun/lwawt/macosx/CFileDialog.java | 3 +-- .../sun/lwawt/macosx/CPrinterDialogPeer.java | 3 +-- .../classes/sun/lwawt/macosx/CPrinterJob.java | 4 ++-- .../com/sun/imageio/stream/StreamCloser.java | 5 ++--- .../java/swing/plaf/windows/WindowsLookAndFeel.java | 3 +-- .../com/sun/media/sound/JSSecurityManager.java | 11 ++++------- .../com/sun/media/sound/SoftAudioPusher.java | 4 +--- .../com/sun/media/sound/SoftJitterCorrector.java | 4 +--- .../com/sun/media/sound/SoftSynthesizer.java | 4 +--- .../share/classes/java/awt/EventDispatchThread.java | 13 ++++++++++--- .../image/renderable/RenderableImageProducer.java | 4 +--- .../share/classes/javax/swing/JTable.java | 3 +-- .../share/classes/javax/swing/TimerQueue.java | 5 ++--- .../javax/swing/plaf/basic/BasicDirectoryModel.java | 3 +-- .../classes/javax/swing/text/JTextComponent.java | 4 ++-- .../share/classes/javax/swing/text/LayoutQueue.java | 3 +-- .../share/classes/sun/applet/AppletClassLoader.java | 12 +++++++++--- .../share/classes/sun/applet/AppletPanel.java | 8 +++----- .../share/classes/sun/applet/AppletViewer.java | 11 ++++++----- .../share/classes/sun/awt/AWTAutoShutdown.java | 5 ++--- .../share/classes/sun/awt/AppContext.java | 5 ++--- .../classes/sun/awt/im/InputMethodManager.java | 4 ++-- .../share/classes/sun/awt/image/ImageFetcher.java | 12 +++++++++--- .../share/classes/sun/font/CreatedFontTracker.java | 5 ++--- .../share/classes/sun/font/SunFontManager.java | 5 ++--- .../share/classes/sun/java2d/Disposer.java | 3 +-- .../classes/sun/java2d/loops/GraphicsPrimitive.java | 6 +++--- .../classes/sun/java2d/opengl/OGLRenderQueue.java | 4 ++-- .../share/classes/sun/print/PrintJob2D.java | 4 ++-- .../share/classes/sun/print/ServiceNotifier.java | 12 +++++++----- .../unix/classes/sun/awt/X11/GtkFileDialogPeer.java | 3 +-- .../unix/classes/sun/awt/X11/InfoWindow.java | 3 +-- .../unix/classes/sun/awt/X11/XTaskbarPeer.java | 7 ++----- .../unix/classes/sun/awt/X11/XToolkit.java | 9 +++++---- .../unix/classes/sun/awt/X11GraphicsDevice.java | 5 ++--- .../sun/print/PrintServiceLookupProvider.java | 5 ++--- .../sun/awt/shell/Win32ShellFolderManager2.java | 11 ++++++----- .../classes/sun/awt/windows/WFileDialogPeer.java | 3 +-- .../classes/sun/awt/windows/WPageDialogPeer.java | 4 +--- .../classes/sun/awt/windows/WPrintDialogPeer.java | 3 +-- .../windows/classes/sun/awt/windows/WToolkit.java | 8 ++++---- .../sun/java2d/d3d/D3DScreenUpdateManager.java | 11 ++++++----- .../sun/print/PrintServiceLookupProvider.java | 5 ++--- 47 files changed, 125 insertions(+), 141 deletions(-) diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java index 05eddcea4d8..f6f1df47ff7 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java @@ -35,7 +35,6 @@ import javax.swing.event.ListDataEvent; import javax.swing.filechooser.FileSystemView; import javax.swing.table.AbstractTableModel; -import sun.misc.ManagedLocalsThread; /** * NavServices-like implementation of a file Table * @@ -393,7 +392,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi this.currentDirectory = currentDirectory; this.fid = fid; String name = "Aqua L&F File Loading Thread"; - this.loadThread = new ManagedLocalsThread(this, name); + this.loadThread = new Thread(null, this, name, 0, false); this.loadThread.start(); } diff --git a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java index 9e883938e46..0c505b28576 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java @@ -42,7 +42,6 @@ import sun.awt.FontConfiguration; import sun.awt.HeadlessToolkit; import sun.awt.util.ThreadGroupUtils; import sun.lwawt.macosx.*; -import sun.misc.ManagedLocalsThread; public final class CFontManager extends SunFontManager { private static Hashtable genericFonts = new Hashtable(); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java index b74719f149b..b7262a5a402 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java @@ -35,7 +35,6 @@ import java.security.*; import java.util.*; import sun.awt.*; -import sun.misc.ManagedLocalsThread; import sun.print.*; import sun.awt.util.ThreadGroupUtils; @@ -77,13 +76,14 @@ public abstract class LWToolkit extends SunToolkit implements Runnable { shutdown(); waitForRunState(STATE_CLEANUP); }; - Thread shutdown = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); + Thread shutdown = new Thread( + ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable, + "AWT-Shutdown", 0, false); shutdown.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdown); String name = "AWT-LW"; - Thread toolkitThread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this, name); + Thread toolkitThread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this, name, 0, false); toolkitThread.setDaemon(true); toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); toolkitThread.start(); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java index 10aef016b0c..0c8d4afc08f 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java @@ -44,7 +44,6 @@ import sun.awt.dnd.*; import sun.lwawt.LWComponentPeer; import sun.lwawt.LWWindowPeer; import sun.lwawt.PlatformWindow; -import sun.misc.ManagedLocalsThread; public final class CDragSourceContextPeer extends SunDragSourceContextPeer { @@ -181,7 +180,7 @@ public final class CDragSourceContextPeer extends SunDragSourceContextPeer { } } }; - new ManagedLocalsThread(dragRunnable).start(); + new Thread(null, dragRunnable, "Drag", 0, false).start(); } catch (Exception e) { final long nativeDragSource = getNativeContext(); setNativeContext(0); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java index 459afae179d..34651baba70 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java @@ -37,7 +37,6 @@ import java.io.*; import sun.awt.CausedFocusEvent.Cause; import sun.awt.AWTAccessor; import sun.java2d.pipe.Region; -import sun.misc.ManagedLocalsThread; import sun.security.action.GetBooleanAction; class CFileDialog implements FileDialogPeer { @@ -120,7 +119,7 @@ class CFileDialog implements FileDialogPeer { if (visible) { // Java2 Dialog class requires peer to run code in a separate thread // and handles keeping the call modal - new ManagedLocalsThread(new Task()).start(); + new Thread(null, new Task(), "FileDialog", 0, false).start(); } // We hide ourself before "show" returns - setVisible(false) // doesn't apply diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java index 1837feb0ccd..cb1ee148707 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java @@ -29,7 +29,6 @@ import java.awt.*; import java.awt.dnd.*; import sun.lwawt.*; -import sun.misc.ManagedLocalsThread; public class CPrinterDialogPeer extends LWWindowPeer { static { @@ -59,7 +58,7 @@ public class CPrinterDialogPeer extends LWWindowPeer { printerDialog.setRetVal(printerDialog.showDialog()); printerDialog.setVisible(false); }; - new ManagedLocalsThread(task).start(); + new Thread(null, task, "PrintDialog", 0, false).start(); } } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index aa00647de21..a22f0c3d15e 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -44,7 +44,6 @@ import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.PageRanges; import sun.java2d.*; -import sun.misc.ManagedLocalsThread; import sun.print.*; public final class CPrinterJob extends RasterPrinterJob { @@ -775,7 +774,8 @@ public final class CPrinterJob extends RasterPrinterJob { // upcall from native private static void detachPrintLoop(final long target, final long arg) { - new ManagedLocalsThread(() -> _safePrintLoop(target, arg)).start(); + new Thread(null, () -> _safePrintLoop(target, arg), + "PrintLoop", 0, false).start(); } private static native void _safePrintLoop(long target, long arg); diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java index 32fa02fe175..f71a481a700 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java @@ -26,7 +26,6 @@ package com.sun.imageio.stream; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; import java.io.IOException; import java.security.AccessController; @@ -92,8 +91,8 @@ public class StreamCloser { * Make its parent the top-level thread group. */ ThreadGroup tg = ThreadGroupUtils.getRootThreadGroup(); - streamCloser = new ManagedLocalsThread(tg, - streamCloserRunnable); + streamCloser = new Thread(tg, streamCloserRunnable, + "StreamCloser", 0, false); /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */ diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java index 5b57582bee9..d27205f3eaf 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java @@ -64,7 +64,6 @@ import sun.awt.SunToolkit; import sun.awt.OSInfo; import sun.awt.shell.ShellFolder; import sun.font.FontUtilities; -import sun.misc.ManagedLocalsThread; import sun.security.action.GetPropertyAction; import sun.swing.DefaultLayoutStyle; @@ -2053,7 +2052,7 @@ public class WindowsLookAndFeel extends BasicLookAndFeel if (audioRunnable != null) { // Runnable appears to block until completed playing, hence // start up another thread to handle playing. - new ManagedLocalsThread(audioRunnable).start(); + new Thread(null, audioRunnable, "Audio", 0, false).start(); } } } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java index 738704facf4..d59118889c2 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java @@ -25,8 +25,6 @@ package com.sun.media.sound; -import sun.misc.ManagedLocalsThread; - import java.io.BufferedInputStream; import java.io.InputStream; import java.io.File; @@ -145,12 +143,11 @@ final class JSSecurityManager { static Thread createThread(final Runnable runnable, final String threadName, final boolean isDaemon, final int priority, - final boolean doStart) { - Thread thread = new ManagedLocalsThread(runnable); + final boolean doStart) + { + String name = (threadName != null) ? threadName : "JSSM Thread"; + Thread thread = new Thread(null, runnable, threadName, 0, false); - if (threadName != null) { - thread.setName(threadName); - } thread.setDaemon(isDaemon); if (priority >= 0) { thread.setPriority(priority); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java index 87f4852714c..3a5e6d9dc1b 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java @@ -24,8 +24,6 @@ */ package com.sun.media.sound; -import sun.misc.ManagedLocalsThread; - import java.io.IOException; import javax.sound.sampled.AudioInputStream; @@ -55,7 +53,7 @@ public final class SoftAudioPusher implements Runnable { if (active) return; active = true; - audiothread = new ManagedLocalsThread(this); + audiothread = new Thread(null, this, "AudioPusher", 0, false); audiothread.setDaemon(true); audiothread.setPriority(Thread.MAX_PRIORITY); audiothread.start(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java index f845a369e0b..61cdf7cdf25 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java @@ -24,8 +24,6 @@ */ package com.sun.media.sound; -import sun.misc.ManagedLocalsThread; - import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import java.io.EOFException; @@ -216,7 +214,7 @@ public final class SoftJitterCorrector extends AudioInputStream { } }; - thread = new ManagedLocalsThread(runnable); + thread = new Thread(null, runnable, "JitterCorrector", 0, false); thread.setDaemon(true); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java index ef2182d6c9e..41b0cffa3df 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java @@ -25,8 +25,6 @@ package com.sun.media.sound; -import sun.misc.ManagedLocalsThread; - import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -141,7 +139,7 @@ public final class SoftSynthesizer implements AudioSynthesizer, pusher = null; jitter_stream = null; sourceDataLine = null; - new ManagedLocalsThread(runnable).start(); + new Thread(null, runnable, "Synthesizer",0,false).start(); } return len; } diff --git a/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java b/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java index 67b4ad852df..d4bead31360 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java +++ b/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java @@ -31,7 +31,6 @@ import java.awt.event.WindowEvent; import java.util.ArrayList; -import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; import sun.awt.dnd.SunDragSourceContextPeer; @@ -55,7 +54,7 @@ import sun.awt.dnd.SunDragSourceContextPeer; * * @since 1.1 */ -class EventDispatchThread extends ManagedLocalsThread { +class EventDispatchThread extends Thread { private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread"); @@ -66,8 +65,16 @@ class EventDispatchThread extends ManagedLocalsThread { private ArrayList eventFilters = new ArrayList(); + /** + * Must always call 5 args super-class constructor passing false + * to indicate not to inherit locals. + */ + private EventDispatchThread() { + throw new UnsupportedOperationException("Must erase locals"); + } + EventDispatchThread(ThreadGroup group, String name, EventQueue queue) { - super(group, name); + super(group, null, name, 0, false); setEventQueue(queue); } diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java b/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java index 77d0b281b43..3eccc740aab 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java +++ b/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java @@ -35,8 +35,6 @@ package java.awt.image.renderable; -import sun.misc.ManagedLocalsThread; - import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.ImageConsumer; @@ -137,7 +135,7 @@ public class RenderableImageProducer implements ImageProducer, Runnable { addConsumer(ic); // Need to build a runnable object for the Thread. String name = "RenderableImageProducer Thread"; - Thread thread = new ManagedLocalsThread(this, name); + Thread thread = new Thread(null, this, name, 0, false); thread.start(); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java index a0111c36c0d..9ca12ea6ee1 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java @@ -56,7 +56,6 @@ import java.util.List; import javax.print.attribute.*; import javax.print.PrintService; -import sun.misc.ManagedLocalsThread; import sun.reflect.misc.ReflectUtil; import sun.swing.SwingUtilities2; @@ -6375,7 +6374,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable }; // start printing on another thread - Thread th = new ManagedLocalsThread(runnable); + Thread th = new Thread(null, runnable, "JTablePrint", 0, false); th.start(); printingStatus.showModal(true); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java b/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java index 5f05a3b6beb..9160b956e95 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java @@ -36,7 +36,6 @@ import java.util.concurrent.*; import java.util.concurrent.locks.*; import java.util.concurrent.atomic.AtomicLong; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; /** * Internal class to manage all Timers using one thread. @@ -101,8 +100,8 @@ class TimerQueue implements Runnable final ThreadGroup threadGroup = AppContext.getAppContext().getThreadGroup(); AccessController.doPrivileged((PrivilegedAction) () -> { String name = "TimerQueue"; - Thread timerThread = new ManagedLocalsThread(threadGroup, - this, name); + Thread timerThread = + new Thread(threadGroup, this, name, 0, false); timerThread.setDaemon(true); timerThread.setPriority(Thread.NORM_PRIORITY); timerThread.start(); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java index d263907f742..a95c82d20fe 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -26,7 +26,6 @@ package javax.swing.plaf.basic; import sun.awt.shell.ShellFolder; -import sun.misc.ManagedLocalsThread; import javax.swing.*; import javax.swing.event.ListDataEvent; @@ -271,7 +270,7 @@ public class BasicDirectoryModel extends AbstractListModel implements Pr this.currentDirectory = currentDirectory; this.fid = fid; String name = "Basic L&F File Loading Thread"; - this.loadThread = new ManagedLocalsThread(this, name); + this.loadThread = new Thread(null, this, name, 0, false); this.loadThread.start(); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java index 571745be89d..3d31a0d1936 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java @@ -70,7 +70,6 @@ import javax.print.attribute.*; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; import sun.swing.PrintingStatus; import sun.swing.SwingUtilities2; import sun.swing.text.TextComponentPrintable; @@ -2353,7 +2352,8 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A runnablePrinting.run(); } else { if (isEventDispatchThread) { - new ManagedLocalsThread(runnablePrinting).start(); + new Thread(null, runnablePrinting, + "JTextComponentPrint", 0, false ).start(); printingStatus.showModal(true); } else { printingStatus.showModal(false); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java b/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java index 7109005c721..6801a84da5b 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java @@ -26,7 +26,6 @@ package javax.swing.text; import java.util.Vector; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; /** * A queue of text layout tasks. @@ -92,7 +91,7 @@ public class LayoutQueue { } } while (work != null); }; - worker = new ManagedLocalsThread(workerRunnable, "text-layout"); + worker = new Thread(null, workerRunnable, "text-layout", 0, false); worker.setPriority(Thread.MIN_PRIORITY); worker.start(); } diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java index a778ca6c769..38a4e93415e 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java @@ -52,7 +52,6 @@ import java.security.Permission; import java.security.PermissionCollection; import sun.awt.AppContext; import sun.awt.SunToolkit; -import sun.misc.ManagedLocalsThread; import sun.net.www.ParseUtil; import sun.security.util.SecurityConstants; @@ -858,13 +857,20 @@ public void grab() { * this operation to complete before continuing, wait for the notifyAll() * operation on the syncObject to occur. */ -class AppContextCreator extends ManagedLocalsThread { +class AppContextCreator extends Thread { Object syncObject = new Object(); AppContext appContext = null; volatile boolean created = false; + /** + * Must call the 5-args super-class constructor to erase locals. + */ + private AppContextCreator() { + throw new UnsupportedOperationException("Must erase locals"); + } + AppContextCreator(ThreadGroup group) { - super(group, "AppContextCreator"); + super(group, null, "AppContextCreator", 0, false); } public void run() { diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java index 7ef9e111171..404131827fe 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java @@ -44,7 +44,6 @@ import sun.awt.AppContext; import sun.awt.EmbeddedFrame; import sun.awt.SunToolkit; import sun.awt.util.PerformanceLogger; -import sun.misc.ManagedLocalsThread; import sun.security.util.SecurityConstants; /** @@ -166,7 +165,7 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { ThreadGroup appletGroup = loader.getThreadGroup(); - handler = new ManagedLocalsThread(appletGroup, this, "thread " + nm); + handler = new Thread(appletGroup, this, "thread " + nm, 0, false); // set the context class loader for this thread AccessController.doPrivileged(new PrivilegedAction() { @Override @@ -396,9 +395,8 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { // until the loader thread terminates. // (one way or another). if (loaderThread == null) { - // REMIND: do we want a name? - //System.out.println("------------------- loading applet"); - setLoaderThread(new ManagedLocalsThread(this)); + setLoaderThread(new Thread(null, this, + "AppletLoader", 0, false)); loaderThread.start(); // we get to go to sleep while this runs loaderThread.join(); diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java index b310b277f93..d613fc94341 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java @@ -38,7 +38,6 @@ import java.security.AccessController; import java.security.PrivilegedAction; import sun.awt.SunToolkit; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; /** * A frame to show the applet tag in. @@ -854,7 +853,7 @@ public class AppletViewer extends Frame implements AppletContext, Printable { // final AppletPanel p = panel; - new ManagedLocalsThread(new Runnable() + new Thread(null, new Runnable() { @Override public void run() @@ -867,7 +866,8 @@ public class AppletViewer extends Frame implements AppletContext, Printable { appletSystemExit(); } } - }).start(); + }, + "AppletCloser", 0, false).start(); } /** @@ -890,7 +890,7 @@ public class AppletViewer extends Frame implements AppletContext, Printable { // spawn a new thread to avoid blocking the event queue // when calling appletShutdown. // - new ManagedLocalsThread(new Runnable() + new Thread(null, new Runnable() { @Override public void run() @@ -901,7 +901,8 @@ public class AppletViewer extends Frame implements AppletContext, Printable { } appletSystemExit(); } - }).start(); + }, + "AppletQuit", 0, false).start(); } /** diff --git a/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java b/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java index 1ecef9162ca..8dd14c78444 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java @@ -34,7 +34,6 @@ import java.util.Map; import java.util.Set; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; /** @@ -337,8 +336,8 @@ public final class AWTAutoShutdown implements Runnable { private void activateBlockerThread() { AccessController.doPrivileged((PrivilegedAction) () -> { String name = "AWT-Shutdown"; - Thread thread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this, name); + Thread thread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this, name, 0, false); thread.setContextClassLoader(null); thread.setDaemon(false); blockerThread = thread; diff --git a/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java b/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java index b4bc32996b2..e966905d2e0 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java @@ -46,7 +46,6 @@ import java.lang.ref.SoftReference; import jdk.internal.misc.JavaAWTAccess; import jdk.internal.misc.SharedSecrets; -import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -598,8 +597,8 @@ public final class AppContext { } public Thread run() { - Thread t = new ManagedLocalsThread(appContext.getThreadGroup(), - runnable, "AppContext Disposer"); + Thread t = new Thread(appContext.getThreadGroup(), + runnable, "AppContext Disposer", 0, false); t.setContextClassLoader(appContext.getContextClassLoader()); t.setPriority(Thread.NORM_PRIORITY + 1); t.setDaemon(true); diff --git a/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java b/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java index 14221d8a909..f61825d8ddf 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java @@ -55,7 +55,6 @@ import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import sun.awt.InputMethodSupport; import sun.awt.SunToolkit; -import sun.misc.ManagedLocalsThread; /** * {@code InputMethodManager} is an abstract class that manages the input @@ -166,7 +165,8 @@ public abstract class InputMethodManager { // to choose from. Otherwise, just keep the instance. if (imm.hasMultipleInputMethods()) { imm.initialize(); - Thread immThread = new ManagedLocalsThread(imm, threadName); + Thread immThread = + new Thread(null, imm, threadName, 0, false); immThread.setDaemon(true); immThread.setPriority(Thread.NORM_PRIORITY + 1); immThread.start(); diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java index 4ad7eea1682..2aca4285977 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java @@ -27,7 +27,6 @@ package sun.awt.image; import java.util.Vector; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; /** * An ImageFetcher is a thread used to fetch ImageFetchable objects. @@ -42,7 +41,7 @@ import sun.misc.ManagedLocalsThread; * @author Jim Graham * @author Fred Ecks */ -class ImageFetcher extends ManagedLocalsThread { +class ImageFetcher extends Thread { static final int HIGH_PRIORITY = 8; static final int LOW_PRIORITY = 3; static final int ANIM_PRIORITY = 2; @@ -51,11 +50,18 @@ class ImageFetcher extends ManagedLocalsThread { // ImageFetchable to be added to the // queue before an ImageFetcher dies + /** + * We must only call the 5 args super() constructor passing + * in "false" to indicate to not inherit locals. + */ + private ImageFetcher() { + throw new UnsupportedOperationException("Must erase locals"); + } /** * Constructor for ImageFetcher -- only called by add() below. */ private ImageFetcher(ThreadGroup threadGroup, int index) { - super(threadGroup, "Image Fetcher " + index); + super(threadGroup, null, "Image Fetcher " + index, 0, false); setDaemon(true); } diff --git a/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java b/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java index 0ce75a7b235..2e239528c71 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java +++ b/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java @@ -36,7 +36,6 @@ import java.util.concurrent.TimeUnit; import sun.awt.AppContext; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; public class CreatedFontTracker { @@ -122,8 +121,8 @@ public class CreatedFontTracker { * Make its parent the top-level thread group. */ ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - t = new ManagedLocalsThread(rootTG, - TempFileDeletionHook::runHooks); + t = new Thread(rootTG, TempFileDeletionHook::runHooks, + "TempFontFileDeleter", 0, false); /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */ diff --git a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java index 67bb3fd383a..19200c8282b 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java +++ b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java @@ -55,7 +55,6 @@ import sun.awt.FontConfiguration; import sun.awt.SunToolkit; import sun.awt.util.ThreadGroupUtils; import sun.java2d.FontSupport; -import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; /** @@ -2513,8 +2512,8 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { }; AccessController.doPrivileged((PrivilegedAction) () -> { ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - fileCloser = new ManagedLocalsThread(rootTG, - fileCloserRunnable); + fileCloser = new Thread(rootTG, fileCloserRunnable, + "FileCloser", 0, false); fileCloser.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(fileCloser); return null; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java b/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java index 01336443bb1..e63da023936 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java @@ -26,7 +26,6 @@ package sun.java2d; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; @@ -85,7 +84,7 @@ public class Disposer implements Runnable { AccessController.doPrivileged((PrivilegedAction) () -> { String name = "Java2D Disposer"; ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - Thread t = new ManagedLocalsThread(rootTG, disposerInstance, name); + Thread t = new Thread(rootTG, disposerInstance, name, 0, false); t.setContextClassLoader(null); t.setDaemon(true); t.setPriority(Thread.MAX_PRIORITY); diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java b/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java index 38bbaeb5178..a71978a10ac 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java @@ -48,7 +48,6 @@ import java.io.FileNotFoundException; import java.security.AccessController; import java.security.PrivilegedAction; -import sun.misc.ManagedLocalsThread; import sun.security.action.GetPropertyAction; /** @@ -420,8 +419,9 @@ public abstract class GraphicsPrimitive { public static void setShutdownHook() { AccessController.doPrivileged((PrivilegedAction) () -> { TraceReporter t = new TraceReporter(); - Thread thread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), t); + Thread thread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), t, + "TraceReporter", 0, false); thread.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(thread); return null; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java index 27abcbd86f8..5a843792f37 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java @@ -28,7 +28,6 @@ package sun.java2d.opengl; import sun.awt.util.ThreadGroupUtils; import sun.java2d.pipe.RenderBuffer; import sun.java2d.pipe.RenderQueue; -import sun.misc.ManagedLocalsThread; import static sun.java2d.pipe.BufferedOpCodes.*; import java.security.AccessController; @@ -161,7 +160,8 @@ public class OGLRenderQueue extends RenderQueue { public QueueFlusher() { String name = "Java2D Queue Flusher"; - thread = new ManagedLocalsThread(ThreadGroupUtils.getRootThreadGroup(), this, name); + thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), + this, name, 0, false); thread.setDaemon(true); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); diff --git a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java index a67fb9be7ce..b62c4eb1298 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -71,7 +71,6 @@ import javax.print.attribute.standard.OrientationRequested; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.PageRanges; -import sun.misc.ManagedLocalsThread; import sun.print.SunPageSelection; import sun.print.SunMinMaxPage; @@ -1009,7 +1008,8 @@ public class PrintJob2D extends PrintJob implements Printable, Runnable { } private void startPrinterJobThread() { - printerJobThread = new ManagedLocalsThread(this, "printerJobThread"); + printerJobThread = + new Thread(null, this, "printerJobThread", 0, false); printerJobThread.start(); } diff --git a/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java b/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java index 573684a6048..8df17defd05 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java +++ b/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java @@ -25,8 +25,6 @@ package sun.print; -import sun.misc.ManagedLocalsThread; - import java.util.Vector; import javax.print.PrintService; @@ -42,15 +40,19 @@ import javax.print.event.PrintServiceAttributeListener; * to obtain the state of the attributes and notifies the listeners of * any changes. */ -class ServiceNotifier extends ManagedLocalsThread { +class ServiceNotifier extends Thread { private PrintService service; private Vector listeners; private boolean stop = false; private PrintServiceAttributeSet lastSet; + /* + * If adding any other constructors, always call the 5-args + * super-class constructor passing "false" for inherit-locals. + */ ServiceNotifier(PrintService service) { - super(service.getName() + " notifier"); + super(null, null, service.getName() + " notifier", 0, false); this.service = service; listeners = new Vector<>(); try { @@ -70,7 +72,7 @@ class ServiceNotifier extends ManagedLocalsThread { } } - void removeListener(PrintServiceAttributeListener listener) { + void removeListener(PrintServiceAttributeListener listener) { synchronized (this) { if (listener == null || listeners == null) { return; diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java index d6ef132fede..fb7688f9b8e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java @@ -29,7 +29,6 @@ import java.awt.peer.FileDialogPeer; import java.io.File; import java.io.FilenameFilter; import sun.awt.AWTAccessor; -import sun.misc.ManagedLocalsThread; /** * FileDialogPeer for the GtkFileChooser. @@ -120,7 +119,7 @@ final class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer { standaloneWindow = 0; fd.setVisible(false); }; - new ManagedLocalsThread(task).start(); + new Thread(null, task, "ShowDialog", 0, false).start(); } else { quit(); fd.setVisible(false); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java index a7870a95b6a..62658c7e92e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java @@ -29,7 +29,6 @@ import java.awt.*; import java.awt.event.*; import java.awt.peer.TrayIconPeer; import sun.awt.*; -import sun.misc.ManagedLocalsThread; import java.awt.image.*; import java.text.BreakIterator; @@ -452,7 +451,7 @@ public abstract class InfoWindow extends Window { final Thread thread; Displayer() { - this.thread = new ManagedLocalsThread(this); + this.thread = new Thread(null, this, "Displayer", 0, false); this.thread.setDaemon(true); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java index bfb964c9b7c..fa23ae0b66e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java @@ -29,7 +29,6 @@ import java.awt.PopupMenu; import java.awt.Taskbar.Feature; import java.awt.peer.TaskbarPeer; import java.awt.event.ActionEvent; -import sun.misc.ManagedLocalsThread; import java.security.AccessController; import sun.security.action.GetPropertyAction; @@ -48,10 +47,8 @@ final class XTaskbarPeer implements TaskbarPeer { new GetPropertyAction("java.desktop.appName", "")); nativeLibraryLoaded = init(dname); if (nativeLibraryLoaded) { - ManagedLocalsThread t - = new ManagedLocalsThread(() -> { - runloop(); - }); + Thread t = new Thread(null, () -> { runloop(); }, + "TaskBar", 0, false); t.setDaemon(true); t.start(); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index f1904e07626..aa460f9f636 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -284,8 +284,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable { } }; String name = "XToolkt-Shutdown-Thread"; - Thread shutdownThread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), r, name); + Thread shutdownThread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), r, name, 0, false); shutdownThread.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdownThread); return null; @@ -332,8 +332,9 @@ public final class XToolkit extends UNIXToolkit implements Runnable { toolkitThread = AccessController.doPrivileged((PrivilegedAction) () -> { String name = "AWT-XAWT"; - Thread thread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this, name); + Thread thread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this, name, + 0, false); thread.setContextClassLoader(null); thread.setPriority(Thread.NORM_PRIORITY + 1); thread.setDaemon(true); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java index 9f35f172014..14ff9a5d45b 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java @@ -44,7 +44,6 @@ import sun.java2d.loops.SurfaceType; import sun.awt.util.ThreadGroupUtils; import sun.java2d.SunGraphicsEnvironment; -import sun.misc.ManagedLocalsThread; /** * This is an implementation of a GraphicsDevice object for a single @@ -442,8 +441,8 @@ public final class X11GraphicsDevice extends GraphicsDevice } }; String name = "Display-Change-Shutdown-Thread-" + screen; - Thread t = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), r, name); + Thread t = new Thread( + ThreadGroupUtils.getRootThreadGroup(), r, name, 0, false); t.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(t); return null; diff --git a/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java b/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java index 7cf6bf0aced..4da098d504e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java +++ b/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java @@ -25,8 +25,6 @@ package sun.print; -import sun.misc.ManagedLocalsThread; - import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStream; @@ -213,7 +211,8 @@ public class PrintServiceLookupProvider extends PrintServiceLookup public PrintServiceLookupProvider() { // start the printer listener thread if (pollServices) { - Thread thr = new ManagedLocalsThread(new PrinterChangeListener()); + Thread thr = new Thread(null, new PrinterChangeListener(), + "PrinterListener", 0, false); thr.setDaemon(true); thr.start(); IPPPrintService.debug_println(debugPrefix+"polling turned on"); diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index b01d04443df..1e20c3582f7 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -41,7 +41,6 @@ import java.util.stream.Stream; import static sun.awt.shell.Win32ShellFolder2.*; import sun.awt.OSInfo; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; // NOTE: This class supersedes Win32ShellFolderManager, which was removed // from distribution after version 1.4.2. @@ -524,8 +523,9 @@ final class Win32ShellFolderManager2 extends ShellFolderManager { return null; }); AccessController.doPrivileged((PrivilegedAction) () -> { - Thread t = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), shutdownHook); + Thread t = new Thread( + ThreadGroupUtils.getRootThreadGroup(), shutdownHook, + "ShellFolder", 0, false); Runtime.getRuntime().addShutdownHook(t); return null; }); @@ -548,8 +548,9 @@ final class Win32ShellFolderManager2 extends ShellFolderManager { * which will not get GCed before VM exit. * Make its parent the top-level thread group. */ - Thread thread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), comRun, name); + Thread thread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), comRun, name, + 0, false); thread.setDaemon(true); return thread; }); diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java index e75f3b9f486..383254b815a 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java @@ -36,7 +36,6 @@ import java.util.MissingResourceException; import java.util.Vector; import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; -import sun.misc.ManagedLocalsThread; final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer { @@ -98,7 +97,7 @@ final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer { @Override public void show() { - new ManagedLocalsThread(this::_show).start(); + new Thread(null, this::_show, "FileDialog", 0, false).start(); } @Override diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java index 10d99948b10..5e7303b1af1 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java @@ -25,8 +25,6 @@ package sun.awt.windows; -import sun.misc.ManagedLocalsThread; - final class WPageDialogPeer extends WPrintDialogPeer { WPageDialogPeer(WPageDialog target) { @@ -53,6 +51,6 @@ final class WPageDialogPeer extends WPrintDialogPeer { } ((WPrintDialog)target).setVisible(false); }; - new ManagedLocalsThread(runnable).start(); + new Thread(null, runnable, "PageDialog", 0, false).start(); } } diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java index 99c727493d1..a80e7dd6d13 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java @@ -32,7 +32,6 @@ import java.awt.dnd.DropTarget; import java.util.Vector; import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; -import sun.misc.ManagedLocalsThread; class WPrintDialogPeer extends WWindowPeer implements DialogPeer { @@ -78,7 +77,7 @@ class WPrintDialogPeer extends WWindowPeer implements DialogPeer { } ((WPrintDialog)target).setVisible(false); }; - new ManagedLocalsThread(runnable).start(); + new Thread(null, runnable, "PrintDialog", 0, false).start(); } synchronized void setHWnd(long hwnd) { diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java index 8fb6f386474..097f68dac31 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java @@ -52,7 +52,6 @@ import sun.awt.datatransfer.DataTransferer; import sun.java2d.d3d.D3DRenderQueue; import sun.java2d.opengl.OGLRenderQueue; -import sun.misc.ManagedLocalsThread; import sun.print.PrintJob2D; import java.awt.dnd.DragSource; @@ -256,7 +255,7 @@ public final class WToolkit extends SunToolkit implements Runnable { (PrivilegedAction) ThreadGroupUtils::getRootThreadGroup); if (!startToolkitThread(this, rootTG)) { String name = "AWT-Windows"; - Thread toolkitThread = new ManagedLocalsThread(rootTG, this, name); + Thread toolkitThread = new Thread(rootTG, this, name, 0, false); toolkitThread.setDaemon(true); toolkitThread.start(); } @@ -283,8 +282,9 @@ public final class WToolkit extends SunToolkit implements Runnable { private void registerShutdownHook() { AccessController.doPrivileged((PrivilegedAction) () -> { - Thread shutdown = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this::shutdown); + Thread shutdown = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this::shutdown, + "ToolkitShutdown", 0, false); shutdown.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdown); return null; diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java index 4b112b9fcc7..62be1e84f1b 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java @@ -49,7 +49,6 @@ import sun.java2d.SurfaceData; import sun.java2d.windows.GDIWindowSurfaceData; import sun.java2d.d3d.D3DSurfaceData.D3DWindowSurfaceData; import sun.java2d.windows.WindowsFlags; -import sun.misc.ManagedLocalsThread; /** * This class handles rendering to the screen with the D3D pipeline. @@ -99,8 +98,9 @@ public class D3DScreenUpdateManager extends ScreenUpdateManager done = true; wakeUpUpdateThread(); }; - Thread shutdown = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); + Thread shutdown = new Thread( + ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable, + "ScreenUpdater", 0, false); shutdown.setContextClassLoader(null); try { Runtime.getRuntime().addShutdownHook(shutdown); @@ -348,8 +348,9 @@ public class D3DScreenUpdateManager extends ScreenUpdateManager if (screenUpdater == null) { screenUpdater = AccessController.doPrivileged((PrivilegedAction) () -> { String name = "D3D Screen Updater"; - Thread t = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this, name); + Thread t = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this, name, + 0, false); // REMIND: should it be higher? t.setPriority(Thread.NORM_PRIORITY + 2); t.setDaemon(true); diff --git a/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java b/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java index e9139b46525..347336bcb7a 100644 --- a/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java +++ b/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java @@ -25,8 +25,6 @@ package sun.print; -import sun.misc.ManagedLocalsThread; - import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; @@ -99,7 +97,8 @@ public class PrintServiceLookupProvider extends PrintServiceLookup { return; } // start the printer listener thread - Thread thr = new ManagedLocalsThread(new PrinterChangeListener()); + Thread thr = new Thread(null, new PrinterChangeListener(), + "PrinterListener", 0, false); thr.setDaemon(true); thr.start(); } /* else condition ought to never happen! */ From c4be81827a38475c8b6766c5417b296db694f2f0 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 5 Apr 2016 10:39:46 +0300 Subject: [PATCH 045/222] 8146301: Enter key does not work in a deserialized JFileChooser Reviewed-by: alexsch, prr --- .../classes/javax/swing/JFileChooser.java | 37 +++++---- .../DeserializedJFileChooserTest.java | 75 +++++++++++++++++++ 2 files changed, 93 insertions(+), 19 deletions(-) create mode 100644 jdk/test/javax/swing/JFileChooser/DeserializedJFileChooser/DeserializedJFileChooserTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java b/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java index 01edf5d0486..b37dd05050a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * 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,13 +26,12 @@ package javax.swing; import javax.swing.event.*; import javax.swing.filechooser.*; +import javax.swing.filechooser.FileFilter; import javax.swing.plaf.FileChooserUI; import javax.accessibility.*; -import java.io.File; -import java.io.ObjectOutputStream; -import java.io.IOException; +import java.io.*; import java.util.Vector; import java.awt.AWTEvent; @@ -51,8 +50,6 @@ import java.beans.JavaBean; import java.beans.BeanProperty; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; -import java.io.InvalidObjectException; -import java.io.ObjectInputStream; import java.lang.ref.WeakReference; /** @@ -390,19 +387,7 @@ public class JFileChooser extends JComponent implements Accessible { } private void installHierarchyListener() { - addHierarchyListener(new HierarchyListener() { - @Override - public void hierarchyChanged(HierarchyEvent e) { - if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) - == HierarchyEvent.PARENT_CHANGED) { - JFileChooser fc = JFileChooser.this; - JRootPane rootPane = SwingUtilities.getRootPane(fc); - if (rootPane != null) { - rootPane.setDefaultButton(fc.getUI().getDefaultButton(fc)); - } - } - } - }); + addHierarchyListener(new FCHierarchyListener()); } private void installShowFilesListener() { @@ -2055,4 +2040,18 @@ public class JFileChooser extends JComponent implements Accessible { } // inner class AccessibleJFileChooser + private class FCHierarchyListener implements HierarchyListener, + Serializable { + @Override + public void hierarchyChanged(HierarchyEvent e) { + if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) + == HierarchyEvent.PARENT_CHANGED) { + JFileChooser fc = JFileChooser.this; + JRootPane rootPane = SwingUtilities.getRootPane(fc); + if (rootPane != null) { + rootPane.setDefaultButton(fc.getUI().getDefaultButton(fc)); + } + } + } + } } diff --git a/jdk/test/javax/swing/JFileChooser/DeserializedJFileChooser/DeserializedJFileChooserTest.java b/jdk/test/javax/swing/JFileChooser/DeserializedJFileChooser/DeserializedJFileChooserTest.java new file mode 100644 index 00000000000..122b819255c --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/DeserializedJFileChooser/DeserializedJFileChooserTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8146301 + * @summary Enter key does not work in a deserialized JFileChooser. + * @run main DeserializedJFileChooserTest + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +public class DeserializedJFileChooserTest { + + private static int state = -1; + private static JFileChooser deserialized; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeLater( () -> { + try { + JFileChooser jfc = new JFileChooser(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(jfc); + oos.close(); + ByteArrayInputStream bis = + new ByteArrayInputStream(bos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bis); + deserialized = (JFileChooser) ois.readObject(); + state = deserialized.showOpenDialog(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + robot.delay(1000); + if (state != JFileChooser.APPROVE_OPTION) { + deserialized.cancelSelection(); + throw new RuntimeException("Failed"); + } + } +} From f0d7d7a5a853972e8c98cdec7697d3ebf643f64c Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 5 Apr 2016 10:47:08 +0300 Subject: [PATCH 046/222] 8149631: rgb(...) CSS color values are not parsed properly Reviewed-by: alexsch --- .../classes/javax/swing/text/html/CSS.java | 14 ++++- .../CSS/ColorValue/RGBColorValueTest.java | 55 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 jdk/test/javax/swing/text/html/CSS/ColorValue/RGBColorValueTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java b/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java index 85cf2a8d16f..06a8ebf6534 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1522,8 +1522,16 @@ public class CSS implements Serializable { current++; } last = current; - while (current < length && !Character.isWhitespace - (value.charAt(current))) { + int inParentheses = 0; + char ch; + while (current < length && ( + !Character.isWhitespace(ch = value.charAt(current)) + || inParentheses > 0)) { + if (ch == '(') { + inParentheses++; + } else if (ch == ')') { + inParentheses--; + } current++; } if (last != current) { diff --git a/jdk/test/javax/swing/text/html/CSS/ColorValue/RGBColorValueTest.java b/jdk/test/javax/swing/text/html/CSS/ColorValue/RGBColorValueTest.java new file mode 100644 index 00000000000..fce9408717d --- /dev/null +++ b/jdk/test/javax/swing/text/html/CSS/ColorValue/RGBColorValueTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + * @test + * @bug 8149631 + * @summary rgb(...) CSS color values are not parsed properly + * @run main RGBColorValueTest + */ + +import javax.swing.text.AttributeSet; +import javax.swing.text.html.StyleSheet; + +import static javax.swing.text.html.CSS.Attribute.*; + +public class RGBColorValueTest { + + public static void main(String[] args) { + StyleSheet styleSheet = new StyleSheet(); + AttributeSet attributeSet = styleSheet. + getDeclaration("border-color: rgb(1, 2, 3) rgb(1, 2, 4);"); + if (!attributeSet.getAttribute(BORDER_TOP_COLOR).toString() + .equals("rgb(1, 2, 3)") || + !attributeSet.getAttribute(BORDER_BOTTOM_COLOR).toString() + .equals("rgb(1, 2, 3)") || + !attributeSet.getAttribute(BORDER_RIGHT_COLOR).toString() + .equals("rgb(1, 2, 4)") || + !attributeSet.getAttribute(BORDER_LEFT_COLOR).toString() + .equals("rgb(1, 2, 4)") ) { + throw new RuntimeException("Failed"); + } + } +} From a120ac732a1010a98ff004858bfb88ce68a8771f Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 5 Apr 2016 10:59:01 +0300 Subject: [PATCH 047/222] 8151333: Some AWT functions may access an array outside of its bounds Reviewed-by: alexsch, prr --- .../native/libawt_xawt/awt/awt_GraphicsEnv.c | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c index 7d2b8b0dbd0..8b64034a295 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1877,31 +1877,34 @@ Java_sun_awt_X11GraphicsDevice_getCurrentDisplayMode AWT_LOCK(); - config = awt_XRRGetScreenInfo(awt_display, - RootWindow(awt_display, screen)); - if (config != NULL) { - Rotation rotation; - short curRate; - SizeID curSizeIndex; - XRRScreenSize *sizes; - int nsizes; + if (screen < ScreenCount(awt_display)) { - curSizeIndex = awt_XRRConfigCurrentConfiguration(config, &rotation); - sizes = awt_XRRConfigSizes(config, &nsizes); - curRate = awt_XRRConfigCurrentRate(config); + config = awt_XRRGetScreenInfo(awt_display, + RootWindow(awt_display, screen)); + if (config != NULL) { + Rotation rotation; + short curRate; + SizeID curSizeIndex; + XRRScreenSize *sizes; + int nsizes; - if ((sizes != NULL) && - (curSizeIndex < nsizes)) - { - XRRScreenSize curSize = sizes[curSizeIndex]; - displayMode = X11GD_CreateDisplayMode(env, - curSize.width, - curSize.height, - BIT_DEPTH_MULTI, - curRate); + curSizeIndex = awt_XRRConfigCurrentConfiguration(config, &rotation); + sizes = awt_XRRConfigSizes(config, &nsizes); + curRate = awt_XRRConfigCurrentRate(config); + + if ((sizes != NULL) && + (curSizeIndex < nsizes)) + { + XRRScreenSize curSize = sizes[curSizeIndex]; + displayMode = X11GD_CreateDisplayMode(env, + curSize.width, + curSize.height, + BIT_DEPTH_MULTI, + curRate); + } + + awt_XRRFreeScreenConfigInfo(config); } - - awt_XRRFreeScreenConfigInfo(config); } AWT_FLUSH_UNLOCK(); From 3b618308c3252fc5dc9bd028325e9e210532bd86 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 5 Apr 2016 14:52:31 +0530 Subject: [PATCH 048/222] 8153363: Redundant check for number of components in PackedColorModel.equals() method Reviewed-by: prr, flar --- .../share/classes/java/awt/image/PackedColorModel.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/PackedColorModel.java b/jdk/src/java.desktop/share/classes/java/awt/image/PackedColorModel.java index c5e8ec8d3ab..0db6ff17441 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/image/PackedColorModel.java +++ b/jdk/src/java.desktop/share/classes/java/awt/image/PackedColorModel.java @@ -404,9 +404,6 @@ public abstract class PackedColorModel extends ColorModel { PackedColorModel cm = (PackedColorModel) obj; int numC = cm.getNumComponents(); - if (numC != numComponents) { - return false; - } for(int i=0; i < numC; i++) { if (maskArray[i] != cm.getMask(i)) { return false; From e4020fda7d28add7b9c7aacce47648754be4f81d Mon Sep 17 00:00:00 2001 From: Avik Niyogi Date: Tue, 5 Apr 2016 15:37:13 +0530 Subject: [PATCH 049/222] 8137169: [macosx] Incorrect minimal heigh of JTabbedPane with more tabs Reviewed-by: rchamyal, alexsch --- .../laf/AquaTabbedPaneCopyFromBasicUI.java | 33 +--- .../8137169/ScrollableTabbedPaneTest.java | 182 ++++++++++++++++++ 2 files changed, 184 insertions(+), 31 deletions(-) create mode 100644 jdk/test/javax/swing/JTabbedPane/8137169/ScrollableTabbedPaneTest.java diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java index 92df95b6db2..d85ed9e8f67 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java @@ -2183,50 +2183,21 @@ public class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements Swing } protected int preferredTabAreaHeight(final int tabPlacement, final int width) { - final FontMetrics metrics = getFontMetrics(); final int tabCount = tabPane.getTabCount(); int total = 0; if (tabCount > 0) { - int rows = 1; - int x = 0; - final int maxTabHeight = calculateMaxTabHeight(tabPlacement); - - for (int i = 0; i < tabCount; i++) { - final int tabWidth = calculateTabWidth(tabPlacement, i, metrics); - - if (x != 0 && x + tabWidth > width) { - rows++; - x = 0; - } - x += tabWidth; - } - total = calculateTabAreaHeight(tabPlacement, rows, maxTabHeight); + total = calculateTabAreaHeight(tabPlacement, 1, maxTabHeight); } return total; } protected int preferredTabAreaWidth(final int tabPlacement, final int height) { - final FontMetrics metrics = getFontMetrics(); final int tabCount = tabPane.getTabCount(); int total = 0; if (tabCount > 0) { - int columns = 1; - int y = 0; - final int fontHeight = metrics.getHeight(); - maxTabWidth = calculateMaxTabWidth(tabPlacement); - - for (int i = 0; i < tabCount; i++) { - final int tabHeight = calculateTabHeight(tabPlacement, i, fontHeight); - - if (y != 0 && y + tabHeight > height) { - columns++; - y = 0; - } - y += tabHeight; - } - total = calculateTabAreaWidth(tabPlacement, columns, maxTabWidth); + total = calculateTabAreaWidth(tabPlacement, 1, maxTabWidth); } return total; } diff --git a/jdk/test/javax/swing/JTabbedPane/8137169/ScrollableTabbedPaneTest.java b/jdk/test/javax/swing/JTabbedPane/8137169/ScrollableTabbedPaneTest.java new file mode 100644 index 00000000000..834da2ef522 --- /dev/null +++ b/jdk/test/javax/swing/JTabbedPane/8137169/ScrollableTabbedPaneTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8137169 + * @summary verifies TabbedScrollPane minimum height for all Look and Feels + * @library ../../regtesthelpers + * @build Util + * @run main ScrollableTabbedPaneTest + */ + +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +public class ScrollableTabbedPaneTest { + + private static JFrame frame; + private static JTabbedPane pane; + private static Robot robot; + private static volatile String errorString = ""; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.delay(1000); + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + executeCase(lookAndFeelItem.getClassName(), + lookAndFeelItem.getName()); + } + if (!"".equals(errorString)) { + throw new RuntimeException("Error Log:\n" + errorString); + } + } + + private static void executeCase(String lookAndFeelString, String shortLAF) + throws Exception { + if (tryLookAndFeel(lookAndFeelString)) { + createUI(shortLAF); + stepsToExecute(shortLAF); + + createLeftUI(shortLAF); + stepsToExecute(shortLAF); + + createRightUI(shortLAF); + stepsToExecute(shortLAF); + } + } + + private static void stepsToExecute(String shortLAF) throws Exception { + robot.delay(100); + runTestCase(shortLAF); + robot.delay(1000); + cleanUp(); + robot.delay(1000); + } + + private static boolean tryLookAndFeel(String lookAndFeelString) + throws Exception { + try { + UIManager.setLookAndFeel( + lookAndFeelString); + + } catch (UnsupportedLookAndFeelException + | ClassNotFoundException + | InstantiationException + | IllegalAccessException e) { + return false; + } + return true; + } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + } + + private static void createUI(final String shortLAF) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame(shortLAF); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + pane = new JTabbedPane(); + pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + frame.add(pane); + frame.setSize(500, 500); + } + }); + } + private static void createLeftUI(final String shortLAF) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame(shortLAF); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + pane = new JTabbedPane(); + pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + pane.setTabPlacement(SwingConstants.LEFT); + frame.add(pane); + frame.setSize(500, 500); + } + }); + } + + private static void createRightUI(final String shortLAF) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame(shortLAF); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + pane = new JTabbedPane(); + pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + pane.setTabPlacement(SwingConstants.RIGHT); + frame.add(pane); + frame.setSize(500, 500); + } + }); + } + + private static void runTestCase(String shortLAF) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + int i = 0; + int value= 0; + do { + String title = "Tab" + (i + 1); + pane.addTab(title, new JPanel()); + int tempValue = pane.getMinimumSize().height; + if(value==0) { + value = tempValue; + } + if(value != tempValue) { + String error = "[" + shortLAF + + "]: [Error]: TabbedScrollPane fails"; + errorString += error; + } + + ++i; + } while (i < 10); + } + }); + } +} + From fe992bb6cdfe3970e5a438f750f0b32cf6061865 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 5 Apr 2016 17:30:23 +0300 Subject: [PATCH 050/222] 8152501: closed/javax/sound/sampled/FileWriter/WaveBigEndian.java failing Reviewed-by: amenkov --- .../sun/media/sound/AudioFloatConverter.java | 109 ++++++++------ .../Bits16ToFromFloatArray.java | 101 +++++++++++++ .../Bits24ToFromFloatArray.java | 126 ++++++++++++++++ .../Bits32ToFromFloatArray.java | 130 ++++++++++++++++ .../Bits64ToFromFloatArray.java | 142 ++++++++++++++++++ .../Bits8ToFromFloatArray.java | 78 ++++++++++ 6 files changed, 640 insertions(+), 46 deletions(-) create mode 100644 jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits16ToFromFloatArray.java create mode 100644 jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits24ToFromFloatArray.java create mode 100644 jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits32ToFromFloatArray.java create mode 100644 jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits64ToFromFloatArray.java create mode 100644 jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits8ToFromFloatArray.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatConverter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatConverter.java index 910e2dc8352..77930d05657 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatConverter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.media.sound; import java.nio.ByteBuffer; @@ -319,8 +320,10 @@ public abstract class AudioFloatConverter { float[] out_buff, int out_offset, int out_len) { int ix = in_offset; int ox = out_offset; - for (int i = 0; i < out_len; i++) - out_buff[ox++] = in_buff[ix++] * (1.0f / 127.0f); + for (int i = 0; i < out_len; i++) { + byte x = in_buff[ix++]; + out_buff[ox++] = x > 0 ? x / 127.0f : x / 128.0f; + } return out_buff; } @@ -328,8 +331,10 @@ public abstract class AudioFloatConverter { byte[] out_buff, int out_offset) { int ix = in_offset; int ox = out_offset; - for (int i = 0; i < in_len; i++) - out_buff[ox++] = (byte) (in_buff[ix++] * 127.0f); + for (int i = 0; i < in_len; i++) { + final float x = in_buff[ix++]; + out_buff[ox++] = (byte) (x > 0 ? x * 127 : x * 128); + } return out_buff; } } @@ -340,9 +345,10 @@ public abstract class AudioFloatConverter { float[] out_buff, int out_offset, int out_len) { int ix = in_offset; int ox = out_offset; - for (int i = 0; i < out_len; i++) - out_buff[ox++] = ((in_buff[ix++] & 0xFF) - 127) - * (1.0f / 127.0f); + for (int i = 0; i < out_len; i++) { + byte x = (byte) (in_buff[ix++] - 128); + out_buff[ox++] = x > 0 ? x / 127.0f : x / 128.0f; + } return out_buff; } @@ -350,8 +356,10 @@ public abstract class AudioFloatConverter { byte[] out_buff, int out_offset) { int ix = in_offset; int ox = out_offset; - for (int i = 0; i < in_len; i++) - out_buff[ox++] = (byte) (127 + in_buff[ix++] * 127.0f); + for (int i = 0; i < in_len; i++) { + float x = in_buff[ix++]; + out_buff[ox++] = (byte) (128 + (x > 0 ? x * 127 : x * 128)); + } return out_buff; } } @@ -369,10 +377,9 @@ public abstract class AudioFloatConverter { int ix = in_offset; int len = out_offset + out_len; for (int ox = out_offset; ox < len; ox++) { - out_buff[ox] = ((short) ((in_buff[ix++] & 0xFF) | - (in_buff[ix++] << 8))) * (1.0f / 32767.0f); + short x = (short) (in_buff[ix++] & 0xFF | (in_buff[ix++] << 8)); + out_buff[ox] = x > 0 ? x / 32767.0f : x / 32768.0f; } - return out_buff; } @@ -381,7 +388,8 @@ public abstract class AudioFloatConverter { int ox = out_offset; int len = in_offset + in_len; for (int ix = in_offset; ix < len; ix++) { - int x = (int) (in_buff[ix] * 32767.0); + float f = in_buff[ix]; + short x = (short) (f > 0 ? f * 32767 : f * 32768); out_buff[ox++] = (byte) x; out_buff[ox++] = (byte) (x >>> 8); } @@ -396,8 +404,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < out_len; i++) { - out_buff[ox++] = ((short) ((in_buff[ix++] << 8) | - (in_buff[ix++] & 0xFF))) * (1.0f / 32767.0f); + short x = (short) ((in_buff[ix++] << 8) | (in_buff[ix++] & 0xFF)); + out_buff[ox++] = x > 0 ? x / 32767.0f : x / 32768.0f; } return out_buff; } @@ -407,7 +415,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * 32767.0); + float f = in_buff[ix++]; + short x = (short) (f > 0 ? f * 32767.0f : f * 32768.0f); out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) x; } @@ -423,7 +432,8 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < out_len; i++) { int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8); - out_buff[ox++] = (x - 32767) * (1.0f / 32767.0f); + x -= 32768; + out_buff[ox++] = x > 0 ? x / 32767.0f : x / 32768.0f; } return out_buff; } @@ -433,7 +443,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = 32767 + (int) (in_buff[ix++] * 32767.0); + float f = in_buff[ix++]; + int x = 32768 + (int) (f > 0 ? f * 32767 : f * 32768); out_buff[ox++] = (byte) x; out_buff[ox++] = (byte) (x >>> 8); } @@ -449,7 +460,8 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < out_len; i++) { int x = ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); - out_buff[ox++] = (x - 32767) * (1.0f / 32767.0f); + x -= 32768; + out_buff[ox++] = x > 0 ? x / 32767.0f : x / 32768.0f; } return out_buff; } @@ -459,7 +471,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = 32767 + (int) (in_buff[ix++] * 32767.0); + float f = in_buff[ix++]; + int x = 32768 + (int) (f > 0 ? f * 32767 : f * 32768); out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) x; } @@ -484,7 +497,7 @@ public abstract class AudioFloatConverter { | ((in_buff[ix++] & 0xFF) << 16); if (x > 0x7FFFFF) x -= 0x1000000; - out_buff[ox++] = x * (1.0f / (float)0x7FFFFF); + out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; } return out_buff; } @@ -494,7 +507,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * (float)0x7FFFFF); + float f = in_buff[ix++]; + int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); if (x < 0) x += 0x1000000; out_buff[ox++] = (byte) x; @@ -516,7 +530,7 @@ public abstract class AudioFloatConverter { | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); if (x > 0x7FFFFF) x -= 0x1000000; - out_buff[ox++] = x * (1.0f / (float)0x7FFFFF); + out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; } return out_buff; } @@ -526,7 +540,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * (float)0x7FFFFF); + float f = in_buff[ix++]; + int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); if (x < 0) x += 0x1000000; out_buff[ox++] = (byte) (x >>> 16); @@ -546,8 +561,8 @@ public abstract class AudioFloatConverter { for (int i = 0; i < out_len; i++) { int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | ((in_buff[ix++] & 0xFF) << 16); - x -= 0x7FFFFF; - out_buff[ox++] = x * (1.0f / (float)0x7FFFFF); + x -= 0x800000; + out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; } return out_buff; } @@ -557,8 +572,9 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * (float)0x7FFFFF); - x += 0x7FFFFF; + float f = in_buff[ix++]; + int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); + x += 0x800000; out_buff[ox++] = (byte) x; out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) (x >>> 16); @@ -576,8 +592,8 @@ public abstract class AudioFloatConverter { for (int i = 0; i < out_len; i++) { int x = ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); - x -= 0x7FFFFF; - out_buff[ox++] = x * (1.0f / (float)0x7FFFFF); + x -= 0x800000; + out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; } return out_buff; } @@ -587,8 +603,9 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * (float)0x7FFFFF); - x += 0x7FFFFF; + float f = in_buff[ix++]; + int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); + x += 8388608; out_buff[ox++] = (byte) (x >>> 16); out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) x; @@ -673,7 +690,7 @@ public abstract class AudioFloatConverter { int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 24); - x -= 0x7FFFFFFF; + x -= 0x80000000; out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); } return out_buff; @@ -685,7 +702,7 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < in_len; i++) { int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); - x += 0x7FFFFFFF; + x += 0x80000000; out_buff[ox++] = (byte) x; out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) (x >>> 16); @@ -706,7 +723,7 @@ public abstract class AudioFloatConverter { int x = ((in_buff[ix++] & 0xFF) << 24) | ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); - x -= 0x7FFFFFFF; + x -= 0x80000000; out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); } return out_buff; @@ -718,7 +735,7 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < in_len; i++) { int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); - x += 0x7FFFFFFF; + x += 0x80000000; out_buff[ox++] = (byte) (x >>> 24); out_buff[ox++] = (byte) (x >>> 16); out_buff[ox++] = (byte) (x >>> 8); @@ -737,7 +754,7 @@ public abstract class AudioFloatConverter { // PCM 32+ bit, signed, little-endian private static class AudioFloatConversion32xSL extends AudioFloatConverter { - final int xbytes; + private final int xbytes; AudioFloatConversion32xSL(int xbytes) { this.xbytes = xbytes; @@ -778,7 +795,7 @@ public abstract class AudioFloatConverter { // PCM 32+ bit, signed, big-endian private static class AudioFloatConversion32xSB extends AudioFloatConverter { - final int xbytes; + private final int xbytes; AudioFloatConversion32xSB(int xbytes) { this.xbytes = xbytes; @@ -820,7 +837,7 @@ public abstract class AudioFloatConverter { // PCM 32+ bit, unsigned, little-endian private static class AudioFloatConversion32xUL extends AudioFloatConverter { - final int xbytes; + private final int xbytes; AudioFloatConversion32xUL(int xbytes) { this.xbytes = xbytes; @@ -835,7 +852,7 @@ public abstract class AudioFloatConverter { int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 24); - x -= 0x7FFFFFFF; + x -= 0x80000000; out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); } return out_buff; @@ -847,7 +864,7 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < in_len; i++) { int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); - x += 0x7FFFFFFF; + x += 0x80000000; for (int j = 0; j < xbytes; j++) { out_buff[ox++] = 0; } @@ -863,7 +880,7 @@ public abstract class AudioFloatConverter { // PCM 32+ bit, unsigned, big-endian private static class AudioFloatConversion32xUB extends AudioFloatConverter { - final int xbytes; + private final int xbytes; AudioFloatConversion32xUB(int xbytes) { this.xbytes = xbytes; @@ -878,7 +895,7 @@ public abstract class AudioFloatConverter { ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); ix += xbytes; - x -= 2147483647; + x -= 0x80000000; out_buff[ox++] = x * (1.0f / 2147483647.0f); } return out_buff; @@ -889,8 +906,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * 2147483647.0); - x += 2147483647; + int x = (int) (in_buff[ix++] * 2147483647.0f); + x += 0x80000000; out_buff[ox++] = (byte) (x >>> 24); out_buff[ox++] = (byte) (x >>> 16); out_buff[ox++] = (byte) (x >>> 8); diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits16ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits16ToFromFloatArray.java new file mode 100644 index 00000000000..54e404dcf6f --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits16ToFromFloatArray.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.*; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits16ToFromFloatArray { + + private static final int SIZE = 16; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static short MID_U = (short) (Short.MAX_VALUE + 1); + private static short MAX_U = -1; + + // BIG ENDIAN + private static final byte[] SIGNED_BIG = { + (byte) (Short.MIN_VALUE >> 8), (byte) (Short.MIN_VALUE & 0xff), 0, + 0, (byte) (Short.MAX_VALUE >> 8), (byte) (Short.MAX_VALUE & 0xff) + }; + + private static final byte[] UNSIGNED_BIG = { + 0, 0, (byte) (MID_U >> 8), (byte) (MID_U & 0xff), + (byte) (MAX_U >> 8), (byte) (MAX_U >> 8) + }; + + // LITTLE ENDIAN + private static final byte[] SIGNED_LITTLE = { + (byte) (Short.MIN_VALUE & 0xff), (byte) (Short.MIN_VALUE >> 8), 0, + 0, (byte) (Short.MAX_VALUE & 0xff), (byte) (Short.MAX_VALUE >> 8) + }; + + private static final byte[] UNSIGNED_LITTLE = { + 0, 0, (byte) (MID_U & 0xff), (byte) (MID_U >> 8), + (byte) (MAX_U >> 8), (byte) (MAX_U >> 8) + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED_BIG, true); + test(PCM_UNSIGNED, UNSIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_BIG, true); + } + + private static void test(final Encoding enc, final byte[] expected, + boolean end) { + System.err.println("enc = " + enc); + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + end); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits24ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits24ToFromFloatArray.java new file mode 100644 index 00000000000..1bd215435d2 --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits24ToFromFloatArray.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED; +import static javax.sound.sampled.AudioFormat.Encoding.PCM_UNSIGNED; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits24ToFromFloatArray { + + private static final int SIZE = 24; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static int MIN_S = -8_388_608; + private static int MAX_S = 8_388_607; + + private static int MID_U = 0xFFFFFF / 2 + 1; + private static int MAX_U = 0xFFFFFF; + + // BIG ENDIAN + private static final byte[] SIGNED_BIG = { + (byte) ((MIN_S >> 16) & 0xff), + (byte) ((MIN_S >> 8) & 0xff), + (byte) ((MIN_S >> 0) & 0xff), + 0, 0, 0, + (byte) ((MAX_S >> 16) & 0xff), + (byte) ((MAX_S >> 8) & 0xff), + (byte) ((MAX_S >> 0) & 0xff), + }; + + private static final byte[] UNSIGNED_BIG = { + 0, 0, 0, + (byte) ((MID_U >> 16) & 0xff), + (byte) ((MID_U >> 8) & 0xff), + (byte) ((MID_U >> 0) & 0xff), + (byte) ((MAX_U >> 16) & 0xff), + (byte) ((MAX_U >> 8) & 0xff), + (byte) ((MAX_U >> 0) & 0xff), + + }; + + // LITTLE ENDIAN + private static final byte[] SIGNED_LITTLE = { + (byte) ((MIN_S >> 0) & 0xff), + (byte) ((MIN_S >> 8) & 0xff), + (byte) ((MIN_S >> 16) & 0xff), + 0, 0, 0, + (byte) ((MAX_S >> 0) & 0xff), + (byte) ((MAX_S >> 8) & 0xff), + (byte) ((MAX_S >> 16) & 0xff), + }; + + private static final byte[] UNSIGNED_LITTLE = { + 0, 0, 0, + (byte) ((MID_U >> 0) & 0xff), + (byte) ((MID_U >> 8) & 0xff), + (byte) ((MID_U >> 16) & 0xff), + (byte) ((MAX_U >> 0) & 0xff), + (byte) ((MAX_U >> 8) & 0xff), + (byte) ((MAX_U >> 16) & 0xff), + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED_BIG, true); + test(PCM_UNSIGNED, UNSIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_BIG, true); + } + + private static void test(final Encoding enc, final byte[] expected, + boolean end) { + System.err.println(enc); + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + end); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits32ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits32ToFromFloatArray.java new file mode 100644 index 00000000000..7a550a54df3 --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits32ToFromFloatArray.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED; +import static javax.sound.sampled.AudioFormat.Encoding.PCM_UNSIGNED; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits32ToFromFloatArray { + + private static final int SIZE = 32; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static int MID_U = (int) (Integer.MAX_VALUE + 1); + private static int MAX_U = -1; + + // BIG ENDIAN + private static final byte[] SIGNED_BIG = { + (byte) ((Integer.MIN_VALUE >> 24) & 0xff), + (byte) ((Integer.MIN_VALUE >> 16) & 0xff), + (byte) ((Integer.MIN_VALUE >> 8) & 0xff), + (byte) ((Integer.MIN_VALUE >> 0) & 0xff), + 0, 0, 0, 0, + (byte) ((Integer.MAX_VALUE >> 24) & 0xff), + (byte) ((Integer.MAX_VALUE >> 16) & 0xff), + (byte) ((Integer.MAX_VALUE >> 8) & 0xff), + (byte) ((Integer.MAX_VALUE >> 0) & 0xff), + }; + + private static final byte[] UNSIGNED_BIG = { + 0, 0, 0, 0, + (byte) ((MID_U >> 24) & 0xff), + (byte) ((MID_U >> 16) & 0xff), + (byte) ((MID_U >> 8) & 0xff), + (byte) ((MID_U >> 0) & 0xff), + (byte) ((MAX_U >> 24) & 0xff), + (byte) ((MAX_U >> 16) & 0xff), + (byte) ((MAX_U >> 8) & 0xff), + (byte) ((MAX_U >> 0) & 0xff), + + }; + + // LITTLE ENDIAN + private static final byte[] SIGNED_LITTLE = { + (byte) ((Integer.MIN_VALUE >> 0) & 0xff), + (byte) ((Integer.MIN_VALUE >> 8) & 0xff), + (byte) ((Integer.MIN_VALUE >> 16) & 0xff), + (byte) ((Integer.MIN_VALUE >> 24) & 0xff), + 0, 0, 0, 0, + (byte) ((Integer.MAX_VALUE >> 0) & 0xff), + (byte) ((Integer.MAX_VALUE >> 8) & 0xff), + (byte) ((Integer.MAX_VALUE >> 16) & 0xff), + (byte) ((Integer.MAX_VALUE >> 24) & 0xff), + }; + + private static final byte[] UNSIGNED_LITTLE = { + 0, 0, 0, 0, + (byte) ((MID_U >> 0) & 0xff), + (byte) ((MID_U >> 8) & 0xff), + (byte) ((MID_U >> 16) & 0xff), + (byte) ((MID_U >> 24) & 0xff), + (byte) ((MAX_U >> 0) & 0xff), + (byte) ((MAX_U >> 8) & 0xff), + (byte) ((MAX_U >> 16) & 0xff), + (byte) ((MAX_U >> 24) & 0xff), + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED_BIG, true); + test(PCM_UNSIGNED, UNSIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_BIG, true); + } + + private static void test(final Encoding enc, final byte[] expected, + boolean end) { + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + end); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits64ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits64ToFromFloatArray.java new file mode 100644 index 00000000000..558835bcb52 --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits64ToFromFloatArray.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED; +import static javax.sound.sampled.AudioFormat.Encoding.PCM_UNSIGNED; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits64ToFromFloatArray { + + private static final int SIZE = 64; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static long MID_U = (long) (Long.MAX_VALUE + 1); + private static long MAX_U = -1; + + // BIG ENDIAN + private static final byte[] SIGNED_BIG = { + (byte) ((Long.MIN_VALUE >> 56) & 0xff), + (byte) ((Long.MIN_VALUE >> 48) & 0xff), + (byte) ((Long.MIN_VALUE >> 40) & 0xff), + (byte) ((Long.MIN_VALUE >> 32) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + 0, 0, 0, 0, + 0, 0, 0, 0, + (byte) ((Long.MAX_VALUE >> 56) & 0xff), + (byte) ((Long.MAX_VALUE >> 48) & 0xff), + (byte) ((Long.MAX_VALUE >> 40) & 0xff), + (byte) ((Long.MAX_VALUE >> 32) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + }; + + private static final byte[] UNSIGNED_BIG = { + 0, 0, 0, 0, + 0, 0, 0, 0, + (byte) ((MID_U >> 56) & 0xff), + (byte) ((MID_U >> 48) & 0xff), + (byte) ((MID_U >> 40) & 0xff), + (byte) ((MID_U >> 32) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((MAX_U >> 56) & 0xff), + (byte) ((MAX_U >> 48) & 0xff), + (byte) ((MAX_U >> 40) & 0xff), + (byte) ((MAX_U >> 32) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + }; + + // LITTLE ENDIAN + private static final byte[] SIGNED_LITTLE = { + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((Long.MIN_VALUE >> 32) & 0xff), + (byte) ((Long.MIN_VALUE >> 40) & 0xff), + (byte) ((Long.MIN_VALUE >> 48) & 0xff), + (byte) ((Long.MIN_VALUE >> 56) & 0xff), + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((Long.MAX_VALUE >> 32) & 0xff), + (byte) ((Long.MAX_VALUE >> 40) & 0xff), + (byte) ((Long.MAX_VALUE >> 48) & 0xff), + (byte) ((Long.MAX_VALUE >> 56) & 0xff), + }; + + private static final byte[] UNSIGNED_LITTLE = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((MID_U >> 32) & 0xff), + (byte) ((MID_U >> 40) & 0xff), + (byte) ((MID_U >> 48) & 0xff), + (byte) ((MID_U >> 56) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((MAX_U >> 32) & 0xff), + (byte) ((MAX_U >> 40) & 0xff), + (byte) ((MAX_U >> 48) & 0xff), + (byte) ((MAX_U >> 56) & 0xff), + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED_BIG, true); + test(PCM_UNSIGNED, UNSIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_BIG, true); + } + + private static void test(final Encoding enc, final byte[] expected, + boolean end) { + System.err.println(enc); + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + end); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits8ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits8ToFromFloatArray.java new file mode 100644 index 00000000000..1d4ab606745 --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits8ToFromFloatArray.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.*; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits8ToFromFloatArray { + + private static final int SIZE = 8; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static final byte[] SIGNED = {Byte.MIN_VALUE, 0, Byte.MAX_VALUE}; + + private static final byte[] UNSIGNED = { + 0, (byte) (Byte.MAX_VALUE + 1), (byte) -1 + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED); + test(PCM_SIGNED, SIGNED); + } + + private static void test(final Encoding enc, final byte[] expected) { + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + true); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} From d5b317c8db1338497269ff3bd17b78bc231507f2 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 5 Apr 2016 17:44:19 +0300 Subject: [PATCH 051/222] 7076354: JavaSoundAudioClip stop() Method sequencer.addMetaEventListener(this); wrong? Reviewed-by: amenkov --- .../share/classes/com/sun/media/sound/JavaSoundAudioClip.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java index 1ac0a54a3d8..ca9ac9c9122 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -232,7 +232,7 @@ public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, L } else if (sequencer != null) { try { sequencerloop = false; - sequencer.addMetaEventListener(this); + sequencer.removeMetaEventListener(this); sequencer.stop(); } catch (Exception e3) { if (Printer.err) e3.printStackTrace(); From 0cd8d72e1d8bfc69b004d1cc17c220e414619134 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 5 Apr 2016 18:11:12 +0300 Subject: [PATCH 052/222] 8144166: [macosx] Test java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java fails Reviewed-by: alexsch --- .../laf/AquaInternalFrameDockIconUI.java | 74 +++++----- .../CompEventOnHiddenComponent.java | 2 +- .../DockIconRepaint/DockIconRepaint.java | 127 ++++++++++++++++++ 3 files changed, 159 insertions(+), 44 deletions(-) create mode 100644 jdk/test/javax/swing/JInternalFrame/DockIconRepaint/DockIconRepaint.java diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameDockIconUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameDockIconUI.java index a24faef499a..af2aaf05ed6 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameDockIconUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameDockIconUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,28 +40,28 @@ import sun.swing.SwingUtilities2; * From MacDockIconUI * * A JRSUI L&F implementation of JInternalFrame.JDesktopIcon - * @author - * @version */ -public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseListener, MouseMotionListener, ComponentListener { - private static final String CACHED_FRAME_ICON_KEY = "apple.laf.internal.frameIcon"; +public final class AquaInternalFrameDockIconUI extends DesktopIconUI + implements MouseListener, MouseMotionListener { - protected JInternalFrame.JDesktopIcon fDesktopIcon; - protected JInternalFrame fFrame; - protected ScaledImageLabel fIconPane; - protected DockLabel fDockLabel; - protected boolean fTrackingIcon = false; + private JInternalFrame.JDesktopIcon fDesktopIcon; + private JInternalFrame fFrame; + private ScaledImageLabel fIconPane; + private DockLabel fDockLabel; + private boolean fTrackingIcon; public static ComponentUI createUI(final JComponent c) { return new AquaInternalFrameDockIconUI(); } + @Override public void installUI(final JComponent c) { fDesktopIcon = (JInternalFrame.JDesktopIcon)c; installComponents(); installListeners(); } + @Override public void uninstallUI(final JComponent c) { uninstallComponents(); uninstallListeners(); @@ -69,55 +69,54 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL fFrame = null; } - protected void installComponents() { + private void installComponents() { fFrame = fDesktopIcon.getInternalFrame(); fIconPane = new ScaledImageLabel(); fDesktopIcon.setLayout(new BorderLayout()); fDesktopIcon.add(fIconPane, BorderLayout.CENTER); } - protected void uninstallComponents() { + private void uninstallComponents() { fDesktopIcon.setLayout(null); fDesktopIcon.remove(fIconPane); } - protected void installListeners() { + private void installListeners() { fDesktopIcon.addMouseListener(this); fDesktopIcon.addMouseMotionListener(this); - fFrame.addComponentListener(this); } - protected void uninstallListeners() { - fFrame.removeComponentListener(this); + private void uninstallListeners() { fDesktopIcon.removeMouseMotionListener(this); fDesktopIcon.removeMouseListener(this); } + @Override public Dimension getMinimumSize(final JComponent c) { return new Dimension(32, 32); } + @Override public Dimension getMaximumSize(final JComponent c) { return new Dimension(128, 128); } + @Override public Dimension getPreferredSize(final JComponent c) { return new Dimension(64, 64); //$ Dock preferred size } - public Insets getInsets(final JComponent c) { - return new Insets(0, 0, 0, 0); - } - void updateIcon() { fIconPane.updateIcon(); } + @Override public void mousePressed(final MouseEvent e) { fTrackingIcon = fIconPane.mouseInIcon(e); if (fTrackingIcon) fIconPane.repaint(); } + @Override public void mouseReleased(final MouseEvent e) {// only when it's actually in the image if (fFrame.isIconifiable() && fFrame.isIcon()) { if (fTrackingIcon) { @@ -137,6 +136,7 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL if (fDockLabel != null && !fIconPane.getBounds().contains(e.getX(), e.getY())) fDockLabel.hide(); } + @Override public void mouseEntered(final MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) return; String title = fFrame.getTitle(); @@ -145,41 +145,27 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL fDockLabel.show(fDesktopIcon); } + @Override public void mouseExited(final MouseEvent e) { if (fDockLabel != null && (e.getModifiers() & InputEvent.BUTTON1_MASK) == 0) fDockLabel.hide(); } + @Override public void mouseClicked(final MouseEvent e) { } + @Override public void mouseDragged(final MouseEvent e) { } + @Override public void mouseMoved(final MouseEvent e) { } - public void componentHidden(final ComponentEvent e) { } - - public void componentMoved(final ComponentEvent e) { } - - public void componentResized(final ComponentEvent e) { - fFrame.putClientProperty(CACHED_FRAME_ICON_KEY, null); - } - - public void componentShown(final ComponentEvent e) { - fFrame.putClientProperty(CACHED_FRAME_ICON_KEY, null); - } - @SuppressWarnings("serial") // Superclass is not serializable across versions - class ScaledImageLabel extends JLabel { + private final class ScaledImageLabel extends JLabel { ScaledImageLabel() { super(null, null, CENTER); } void updateIcon() { - final Object priorIcon = fFrame.getClientProperty(CACHED_FRAME_ICON_KEY); - if (priorIcon instanceof ImageIcon) { - setIcon((ImageIcon)priorIcon); - return; - } - int width = fFrame.getWidth(); int height = fFrame.getHeight(); @@ -196,11 +182,10 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL final float scale = (float)fDesktopIcon.getWidth() / (float)Math.max(width, height) * 0.89f; // Sending in -1 for width xor height causes it to maintain aspect ratio - final ImageIcon icon = new ImageIcon(fImage.getScaledInstance((int)(width * scale), -1, Image.SCALE_SMOOTH)); - fFrame.putClientProperty(CACHED_FRAME_ICON_KEY, icon); - setIcon(icon); + setIcon(new ImageIcon(fImage.getScaledInstance((int)(width * scale), -1, Image.SCALE_SMOOTH))); } + @Override public void paint(final Graphics g) { if (getIcon() == null) updateIcon(); @@ -222,13 +207,14 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL return getBounds().contains(e.getX(), e.getY()); } + @Override public Dimension getPreferredSize() { return new Dimension(64, 64); //$ Dock preferred size } } @SuppressWarnings("serial") // Superclass is not serializable across versions - class DockLabel extends JLabel { + private static final class DockLabel extends JLabel { static final int NUB_HEIGHT = 7; static final int ROUND_ADDITIONAL_HEIGHT = 8; static final int ROUND_ADDITIONAL_WIDTH = 12; @@ -243,6 +229,7 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL setSize(SwingUtilities.computeStringWidth(metrics, getText()) + ROUND_ADDITIONAL_WIDTH * 2, metrics.getAscent() + NUB_HEIGHT + ROUND_ADDITIONAL_HEIGHT); } + @Override public void paint(final Graphics g) { final int width = getWidth(); final int height = getHeight(); @@ -303,6 +290,7 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL } } + @Override @Deprecated public void hide() { final Container parent = getParent(); diff --git a/jdk/test/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java b/jdk/test/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java index 43a6d326702..cd74e128b7c 100644 --- a/jdk/test/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java +++ b/jdk/test/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java @@ -25,7 +25,7 @@ /* @test - @bug 6383903 + @bug 6383903 8144166 @summary REGRESSION: componentMoved is now getting called for some hidden components @author andrei.dmitriev: area=awt.component @run main CompEventOnHiddenComponent diff --git a/jdk/test/javax/swing/JInternalFrame/DockIconRepaint/DockIconRepaint.java b/jdk/test/javax/swing/JInternalFrame/DockIconRepaint/DockIconRepaint.java new file mode 100644 index 00000000000..6af5c95e473 --- /dev/null +++ b/jdk/test/javax/swing/JInternalFrame/DockIconRepaint/DockIconRepaint.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.beans.PropertyVetoException; + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JPanel; + +/** + * @test + * @bug 8144166 + * @requires (os.family == "mac") + */ +public final class DockIconRepaint { + + private static volatile Color color; + + private static JFrame frame; + + private static JInternalFrame jif; + + private static Robot robot; + + private static Point iconLoc; + + private static Rectangle iconBounds; + + public static void main(final String[] args) throws Exception { + robot = new Robot(); + EventQueue.invokeAndWait(DockIconRepaint::createUI); + try { + robot.waitForIdle(); + color = Color.BLUE; + test(); + color = Color.RED; + test(); + color = Color.GREEN; + test(); + } finally { + frame.dispose(); + } + } + + private static void test() throws Exception { + // maximize the frame to force repaint + EventQueue.invokeAndWait(() -> { + try { + jif.setIcon(false); + jif.setMaximum(true); + } catch (PropertyVetoException e) { + throw new RuntimeException(e); + } + }); + robot.waitForIdle(); + Thread.sleep(1000); + // minimize the frame to dock, the icon should be up2date + EventQueue.invokeAndWait(() -> { + try { + jif.setIcon(true); + } catch (PropertyVetoException e) { + throw new RuntimeException(e); + } + iconLoc = jif.getDesktopIcon().getLocationOnScreen(); + iconBounds = jif.getDesktopIcon().getBounds(); + }); + robot.waitForIdle(); + Thread.sleep(1000); + + final Color c = robot.getPixelColor(iconLoc.x + iconBounds.width / 2, + iconLoc.y + iconBounds.height / 2); + if (c.getRGB() != color.getRGB()) { + System.err.println("Exp: " + Integer.toHexString(color.getRGB())); + System.err.println("Actual: " + Integer.toHexString(c.getRGB())); + throw new RuntimeException("Wrong color."); + } + } + + private static void createUI() { + frame = new JFrame(); + frame.setUndecorated(true); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + final JDesktopPane pane = new JDesktopPane(); + final JPanel panel = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + g.setColor(color); + g.fillRect(0, 0, getWidth(), getHeight()); + } + }; + jif = new JInternalFrame(); + jif.add(panel); + jif.setVisible(true); + jif.setSize(300, 300); + pane.add(jif); + frame.add(pane); + frame.setVisible(true); + } +} From c06119d8ae9d68279b795152e5c73c8bb3936537 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 5 Apr 2016 18:23:10 +0300 Subject: [PATCH 053/222] 8151773: [macosx] TrayIcon.imageAutoSize property is ignored Reviewed-by: alexsch --- .../native/libawt_lwawt/awt/CTrayIcon.m | 23 +++++++++++-------- .../MultiResolutionTrayIconTest.java | 3 +-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m index 73d4c2f7896..36d13667f55 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * 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,18 +39,21 @@ * If the image of the specified size won't fit into the status bar, * then scale it down proprtionally. Otherwise, leave it as is. */ -static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { +static NSSize ScaledImageSizeForStatusBar(NSSize imageSize, BOOL autosize) { NSRect imageRect = NSMakeRect(0.0, 0.0, imageSize.width, imageSize.height); // There is a black line at the bottom of the status bar // that we don't want to cover with image pixels. - CGFloat desiredHeight = [[NSStatusBar systemStatusBar] thickness] - 1.0; - CGFloat scaleFactor = MIN(1.0, desiredHeight/imageSize.height); - - imageRect.size.width *= scaleFactor; - imageRect.size.height *= scaleFactor; + CGFloat desiredSize = [[NSStatusBar systemStatusBar] thickness] - 1.0; + if (autosize) { + imageRect.size.width = desiredSize; + imageRect.size.height = desiredSize; + } else { + CGFloat scaleFactor = MIN(1.0, desiredSize/imageSize.height); + imageRect.size.width *= scaleFactor; + imageRect.size.height *= scaleFactor; + } imageRect = NSIntegralRect(imageRect); - return imageRect.size; } @@ -101,9 +104,9 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { return peer; } -- (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize{ +- (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize { NSSize imageSize = [imagePtr size]; - NSSize scaledSize = ScaledImageSizeForStatusBar(imageSize); + NSSize scaledSize = ScaledImageSizeForStatusBar(imageSize, autosize); if (imageSize.width != scaledSize.width || imageSize.height != scaledSize.height) { [imagePtr setSize: scaledSize]; diff --git a/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java index 87a6de00917..bb0a7525ec7 100644 --- a/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java +++ b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java @@ -24,8 +24,7 @@ /* @test - @bug 8150176 - @ignore 8150176 + @bug 8150176 8151773 @summary Check if correct resolution variant is used for tray icon. @author a.stepanov @run applet/manual=yesno MultiResolutionTrayIconTest.html From 54ba9a6358cc922df30a1113f33aabfc2b32ddb3 Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Tue, 5 Apr 2016 21:13:44 +0400 Subject: [PATCH 054/222] 6949414: JMenu.buildMenuElementArray() endless loop 6424606: behavior of returned from MenuSelectionManager.defaultManager() object is inconsistent with spec Reviewed-by: serb, ssadetsky --- .../share/classes/javax/swing/JMenu.java | 11 ++-- .../swing/plaf/basic/BasicPopupMenuUI.java | 8 ++- .../6949414/JPopupMenuEndlessLoopTest.java | 59 +++++++++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 jdk/test/javax/swing/JPopupMenu/6949414/JPopupMenuEndlessLoopTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JMenu.java b/jdk/src/java.desktop/share/classes/javax/swing/JMenu.java index c9a279a5ed0..643f2c85ecb 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JMenu.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JMenu.java @@ -1296,7 +1296,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @return the array of menu items */ private MenuElement[] buildMenuElementArray(JMenu leaf) { - Vector elements = new Vector(); + Vector elements = new Vector<>(); Component current = leaf.getPopupMenu(); JPopupMenu pop; JMenu menu; @@ -1314,11 +1314,14 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement } else if (current instanceof JMenuBar) { bar = (JMenuBar) current; elements.insertElementAt(bar, 0); - MenuElement me[] = new MenuElement[elements.size()]; - elements.copyInto(me); - return me; + break; + } else { + break; } } + MenuElement me[] = new MenuElement[elements.size()]; + elements.copyInto(me); + return me; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java index 4a4d0baf32b..1b6c56c2fc0 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -797,9 +797,11 @@ public class BasicPopupMenuUI extends PopupMenuUI { if (invoker instanceof JPopupMenu) { invoker = ((JPopupMenu)invoker).getInvoker(); } - grabbedWindow = invoker instanceof Window? - (Window)invoker : - SwingUtilities.getWindowAncestor(invoker); + grabbedWindow = (invoker == null) + ? null + : ((invoker instanceof Window) + ? (Window) invoker + : SwingUtilities.getWindowAncestor(invoker)); if(grabbedWindow != null) { if(tk instanceof sun.awt.SunToolkit) { ((sun.awt.SunToolkit)tk).grab(grabbedWindow); diff --git a/jdk/test/javax/swing/JPopupMenu/6949414/JPopupMenuEndlessLoopTest.java b/jdk/test/javax/swing/JPopupMenu/6949414/JPopupMenuEndlessLoopTest.java new file mode 100644 index 00000000000..0a0df91379f --- /dev/null +++ b/jdk/test/javax/swing/JPopupMenu/6949414/JPopupMenuEndlessLoopTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 6949414 6424606 + * @summary JMenu.buildMenuElementArray() endless loop + * @run main/timeout=5 JPopupMenuEndlessLoopTest + */ +public class JPopupMenuEndlessLoopTest { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + + JPopupMenu popup = new JPopupMenu("Popup Menu"); + JMenu menu = new JMenu("Menu"); + menu.add(new JMenuItem("Menu Item")); + popup.add(menu); + menu.doClick(); + MenuElement[] elems = MenuSelectionManager + .defaultManager().getSelectedPath(); + + if (elems == null || elems.length == 0) { + throw new RuntimeException("Empty Selection"); + } + + if (elems[0] != popup || elems[1] != menu) { + throw new RuntimeException("Necessary menus are not selected!"); + } + }); + } +} From 2479abaae737d824ddf0d3ec0fb0f21f37308cd9 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 5 Apr 2016 11:52:52 -0700 Subject: [PATCH 055/222] 8146324: Add sun.font.FontUtilities.isComplexCharCode or related method Reviewed-by: serb, ssadetsky --- .../share/classes/java/awt/Font.java | 43 ++++++++++ .../share/classes/sun/font/FontUtilities.java | 19 +++++ .../awt/FontClass/TextRequiresLayoutTest.java | 85 +++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 jdk/test/java/awt/FontClass/TextRequiresLayoutTest.java diff --git a/jdk/src/java.desktop/share/classes/java/awt/Font.java b/jdk/src/java.desktop/share/classes/java/awt/Font.java index 8edd2227bad..29ce9f1a084 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Font.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Font.java @@ -765,6 +765,49 @@ public class Font implements java.io.Serializable this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); } + /** + * Returns true if any part of the specified text is from a + * complex script for which the implementation will need to invoke + * layout processing in order to render correctly when using + * {@link Graphics#drawString(String,int,int) drawString(String,int,int)} + * and other text rendering methods. Measurement of the text + * may similarly need the same extra processing. + * The {@code start} and {@code end} indices are provided so that + * the application can request only a subset of the text be considered. + * The last char index examined is at {@code "end-1"}, + * i.e a request to examine the entire array would be + *
    +     * {@code Font.textRequiresLayout(chars, 0, chars.length);}
    +     * 
    + * An application may find this information helpful in + * performance sensitive code. + *

    + * Note that even if this method returns {@code false}, layout processing + * may still be invoked when used with any {@code Font} + * for which {@link #hasLayoutAttributes()} returns {@code true}, + * so that method will need to be consulted for the specific font, + * in order to obtain an answer which accounts for such font attributes. + * + * @param chars the text. + * @param start the index of the first char to examine. + * @param end the ending index, exclusive. + * @return {@code true} if the specified text will need special layout. + * @throws NullPointerException if {@code chars} is null. + * @throws ArrayIndexOutOfBoundsException if {@code start} is negative or + * {@code end} is greater than the length of the {@code chars} array. + * @since 9 + */ + public static boolean textRequiresLayout(char[] chars, + int start, int end) { + if (chars == null) { + throw new NullPointerException("null char array"); + } + if (start < 0 || end > chars.length) { + throw new ArrayIndexOutOfBoundsException("start < 0 or end > len"); + } + return FontUtilities.isComplexScript(chars, start, end); + } + /** * Returns a {@code Font} appropriate to the attributes. * If {@code attributes} contains a {@code FONT} attribute diff --git a/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java b/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java index 3aec0a72d89..bfbd4559448 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java +++ b/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java @@ -182,6 +182,25 @@ public final class FontUtilities { return FontAccess.getFontAccess().getFont2D(font); } + /** + * Return true if there any characters which would trigger layout. + * This method considers supplementary characters to be simple, + * since we do not presently invoke layout on any code points in + * outside the BMP. + */ + public static boolean isComplexScript(char [] chs, int start, int limit) { + + for (int i = start; i < limit; i++) { + if (chs[i] < MIN_LAYOUT_CHARCODE) { + continue; + } + else if (isComplexCharCode(chs[i])) { + return true; + } + } + return false; + } + /** * If there is anything in the text which triggers a case * where char->glyph does not map 1:1 in straightforward diff --git a/jdk/test/java/awt/FontClass/TextRequiresLayoutTest.java b/jdk/test/java/awt/FontClass/TextRequiresLayoutTest.java new file mode 100644 index 00000000000..99b2595c41b --- /dev/null +++ b/jdk/test/java/awt/FontClass/TextRequiresLayoutTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8146324 + * @summary Test Font.textRequiresLayout + */ + +import java.awt.Font; + +public class TextRequiresLayoutTest { + + public static void main(String args[]) { + + String simpleStr = "Hello World"; + String complexStr = "\u0641\u0642\u0643"; + char[] simpleChars = simpleStr.toCharArray(); + char[] complexChars = complexStr.toCharArray(); + + if (Font.textRequiresLayout(simpleChars, 0, simpleChars.length)) { + throw new RuntimeException("Simple text should not need layout"); + } + + if (!Font.textRequiresLayout(complexChars, 0, complexChars.length)) { + throw new RuntimeException("Complex text should need layout"); + } + + if (Font.textRequiresLayout(complexChars, 0, 0)) { + throw new RuntimeException("Empty text should not need layout"); + } + + boolean except = false; + try { + Font.textRequiresLayout(null, 0, 0); + } catch (NullPointerException npe) { + except = true; + } + if (!except) { + throw new RuntimeException("No expected IllegalArgumentException"); + } + + except = false; + try { + Font.textRequiresLayout(complexChars, -1, 0); + } catch (ArrayIndexOutOfBoundsException aioobe) { + except = true; + } + if (!except) { + throw new + RuntimeException("No expected ArrayIndexOutOfBoundsException"); + } + + except = false; + try { + Font.textRequiresLayout(complexChars, 0, complexChars.length+1); + } catch (ArrayIndexOutOfBoundsException aioobe) { + except = true; + } + if (!except) { + throw new + RuntimeException("No expected ArrayIndexOutOfBoundsException"); + } + } +} From d69d30499a70736971a2e653b86e21a2bcb4f383 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 6 Apr 2016 12:25:21 +0530 Subject: [PATCH 056/222] 8044289: In ImageIO.write() and ImageIO.read() null stream is not handled properly Reviewed-by: prr, serb, psadhukhan --- .../share/classes/javax/imageio/ImageIO.java | 46 ++-- .../imageio/stream/NullStreamCheckTest.java | 202 ++++++++++++++++++ 2 files changed, 230 insertions(+), 18 deletions(-) create mode 100644 jdk/test/javax/imageio/stream/NullStreamCheckTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java b/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java index ae480b9c002..7af7b77be77 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java @@ -1294,7 +1294,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if {@code input} is * {@code null}. - * @exception IOException if an error occurs during reading. + * @exception IOException if an error occurs during reading or when not + * able to create required ImageInputStream. */ public static BufferedImage read(File input) throws IOException { if (input == null) { @@ -1344,7 +1345,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if {@code input} is * {@code null}. - * @exception IOException if an error occurs during reading. + * @exception IOException if an error occurs during reading or when not + * able to create required ImageInputStream. */ public static BufferedImage read(InputStream input) throws IOException { if (input == null) { @@ -1352,6 +1354,9 @@ public final class ImageIO { } ImageInputStream stream = createImageInputStream(input); + if (stream == null) { + throw new IIOException("Can't create an ImageInputStream!"); + } BufferedImage bi = read(stream); if (bi == null) { stream.close(); @@ -1384,7 +1389,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if {@code input} is * {@code null}. - * @exception IOException if an error occurs during reading. + * @exception IOException if an error occurs during reading or when not + * able to create required ImageInputStream. */ public static BufferedImage read(URL input) throws IOException { if (input == null) { @@ -1398,6 +1404,14 @@ public final class ImageIO { throw new IIOException("Can't get input stream from URL!", e); } ImageInputStream stream = createImageInputStream(istream); + if (stream == null) { + /* close the istream when stream is null so that if user has + * given filepath as URL he can delete it, otherwise stream will + * be open to that file and he will not be able to delete it. + */ + istream.close(); + throw new IIOException("Can't create an ImageInputStream!"); + } BufferedImage bi; try { bi = read(stream); @@ -1510,7 +1524,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if any parameter is * {@code null}. - * @exception IOException if an error occurs during writing. + * @exception IOException if an error occurs during writing or when not + * able to create required ImageOutputStream. */ public static boolean write(RenderedImage im, String formatName, @@ -1518,7 +1533,6 @@ public final class ImageIO { if (output == null) { throw new IllegalArgumentException("output == null!"); } - ImageOutputStream stream = null; ImageWriter writer = getWriter(im, formatName); if (writer == null) { @@ -1528,13 +1542,11 @@ public final class ImageIO { return false; } - try { - output.delete(); - stream = createImageOutputStream(output); - } catch (IOException e) { - throw new IIOException("Can't create output stream!", e); + output.delete(); + ImageOutputStream stream = createImageOutputStream(output); + if (stream == null) { + throw new IIOException("Can't create an ImageOutputStream!"); } - try { return doWrite(im, writer, stream); } finally { @@ -1562,7 +1574,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if any parameter is * {@code null}. - * @exception IOException if an error occurs during writing. + * @exception IOException if an error occurs during writing or when not + * able to create required ImageOutputStream. */ public static boolean write(RenderedImage im, String formatName, @@ -1570,13 +1583,10 @@ public final class ImageIO { if (output == null) { throw new IllegalArgumentException("output == null!"); } - ImageOutputStream stream = null; - try { - stream = createImageOutputStream(output); - } catch (IOException e) { - throw new IIOException("Can't create output stream!", e); + ImageOutputStream stream = createImageOutputStream(output); + if (stream == null) { + throw new IIOException("Can't create an ImageOutputStream!"); } - try { return doWrite(im, getWriter(im, formatName), stream); } finally { diff --git a/jdk/test/javax/imageio/stream/NullStreamCheckTest.java b/jdk/test/javax/imageio/stream/NullStreamCheckTest.java new file mode 100644 index 00000000000..f763b9de1e6 --- /dev/null +++ b/jdk/test/javax/imageio/stream/NullStreamCheckTest.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8044289 + * @summary Test verifies that when some of the read() and write() methods + * are not able to get stream from createImageInputStream() and + * createImageOutputStream() are we doing null check for stream + * and throwing IOException as per specification. + * @run main NullStreamCheckTest + */ + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import javax.imageio.ImageIO; +import javax.imageio.spi.IIORegistry; +import javax.imageio.spi.ImageInputStreamSpi; +import javax.imageio.spi.ImageOutputStreamSpi; + +public class NullStreamCheckTest { + + // get ImageIORegistry default instance. + private static final IIORegistry localRegistry = IIORegistry. + getDefaultInstance(); + // stream variables needed for input and output. + static LocalOutputStream outputStream = new LocalOutputStream(); + static LocalInputStream inputStream = new LocalInputStream(); + + static final int width = 50, height = 50; + + // input and output BufferedImage needed while read and write. + static BufferedImage inputImage = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + + // creates test file needed for read and write in local directory. + private static File createTestFile(String name) throws IOException { + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String filePath = dir+sep; + File directory = new File(filePath); + File tmpTestFile = File.createTempFile(name, ".png", directory); + directory.delete(); + return tmpTestFile; + } + + /* if we catch expected IOException message return + * false otherwise return true. + */ + private static boolean verifyOutputExceptionMessage(IOException ex) { + String message = ex.getMessage(); + return (!message.equals("Can't create an ImageOutputStream!")); + } + + /* if we catch expected IOException message return + * false otherwise return true. + */ + private static boolean verifyInputExceptionMessage(IOException ex) { + String message = ex.getMessage(); + return (!message.equals("Can't create an ImageInputStream!")); + } + + private static void verifyFileWrite() throws IOException { + File outputTestFile = createTestFile("outputTestFile"); + try { + ImageIO.write(inputImage, "png", outputTestFile); + } catch (IOException ex) { + if (verifyOutputExceptionMessage(ex)) + throw ex; + } finally { + outputTestFile.delete(); + } + } + + private static void verifyStreamWrite() throws IOException { + try { + ImageIO.write(inputImage, "png", outputStream); + } catch (IOException ex) { + if (verifyOutputExceptionMessage(ex)) + throw ex; + } finally { + try { + outputStream.close(); + } catch (IOException ex) { + throw ex; + } + } + } + + private static void verifyFileRead() throws IOException { + File inputTestFile = createTestFile("inputTestFile"); + try { + ImageIO.read(inputTestFile); + } catch (IOException ex) { + if (verifyInputExceptionMessage(ex)) + throw ex; + } finally { + inputTestFile.delete(); + } + } + + private static void verifyStreamRead() throws IOException { + try { + ImageIO.read(inputStream); + } catch (IOException ex) { + if (verifyInputExceptionMessage(ex)) + throw ex; + } finally { + try { + inputStream.close(); + } catch (IOException ex) { + throw ex; + } + } + } + + private static void verifyUrlRead() throws IOException { + URL url; + File inputTestUrlFile = createTestFile("inputTestFile"); + try { + try { + url = inputTestUrlFile.toURI().toURL(); + } catch (MalformedURLException ex) { + throw ex; + } + + try { + ImageIO.read(url); + } catch (IOException ex) { + if (verifyInputExceptionMessage(ex)) + throw ex; + } + } finally { + inputTestUrlFile.delete(); + } + } + + public static void main(String[] args) throws IOException, + MalformedURLException { + + /* deregister ImageOutputStreamSpi so that we creatImageOutputStream + * returns null while writing. + */ + localRegistry.deregisterAll(ImageOutputStreamSpi.class); + /* verify possible ImageIO.write() scenario's for null stream output + * from createImageOutputStream() API in ImageIO class. + */ + verifyFileWrite(); + verifyStreamWrite(); + + /* deregister ImageInputStreamSpi so that we creatImageInputStream + * returns null while reading. + */ + localRegistry.deregisterAll(ImageInputStreamSpi.class); + /* verify possible ImageIO.read() scenario's for null stream output + * from createImageInputStream API in ImageIO class. + */ + verifyFileRead(); + verifyStreamRead(); + verifyUrlRead(); + } + + static class LocalOutputStream extends OutputStream { + + @Override + public void write(int i) throws IOException { + } + } + + static class LocalInputStream extends InputStream { + + @Override + public int read() throws IOException { + return 0; + } + } +} From d3b1596a8b9abbae5b7f52d75c69e683785ea9d0 Mon Sep 17 00:00:00 2001 From: Alexander Kulyakhtin Date: Wed, 6 Apr 2016 13:47:18 +0300 Subject: [PATCH 057/222] 8153584: New jtreg test to verify PathSearchingVirutalMachine.bootClassPath() behaviour Adding a new jtreg test Reviewed-by: dsamersoff --- .../sun/jdi/SunBootClassPathEmptyTest.java | 97 +++++++++++++++++++ jdk/test/com/sun/jdi/TestClass.java | 30 ++++++ 2 files changed, 127 insertions(+) create mode 100644 jdk/test/com/sun/jdi/SunBootClassPathEmptyTest.java create mode 100644 jdk/test/com/sun/jdi/TestClass.java diff --git a/jdk/test/com/sun/jdi/SunBootClassPathEmptyTest.java b/jdk/test/com/sun/jdi/SunBootClassPathEmptyTest.java new file mode 100644 index 00000000000..e062996ee6a --- /dev/null +++ b/jdk/test/com/sun/jdi/SunBootClassPathEmptyTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.sun.jdi.connect.*; +import com.sun.jdi.*; +import java.util.Map; +import java.util.List; +import jdk.test.lib.Asserts; + +/* + * @test + * @summary Verifies that PathSearchingVirtualMachine.bootClassPath() + * returns an empty list in case no bootclass path specified + * regardless of sun.boot.class.path option, which is now obsolete + * @library /test/lib/share/classes + * @compile TestClass.java + * @compile SunBootClassPathEmptyTest.java + * @run main/othervm SunBootClassPathEmptyTest + */ +public class SunBootClassPathEmptyTest { + + /** + * Helper class to facilitate the debuggee VM launching + */ + private static class VmConnector { + + LaunchingConnector lc; + VirtualMachine vm; + + VmConnector() { + for (LaunchingConnector c : Bootstrap.virtualMachineManager().launchingConnectors()) { + System.out.println("name: " + c.name()); + if (c.name().equals("com.sun.jdi.CommandLineLaunch")) { + lc = c; + break; + } + } + if (lc == null) { + throw new RuntimeException("Connector not found"); + } + } + + PathSearchingVirtualMachine launchVm(String cmdLine, String options) throws Exception { + Map vmArgs = lc.defaultArguments(); + vmArgs.get("main").setValue(cmdLine); + if (options != null) { + vmArgs.get("options").setValue(options); + } + System.out.println("Debugger is launching vm ..."); + vm = lc.launch(vmArgs); + if (!(vm instanceof PathSearchingVirtualMachine)) { + throw new RuntimeException("VM is not a PathSearchingVirtualMachine"); + } + return (PathSearchingVirtualMachine) vm; + } + + } + + private static VmConnector connector = new VmConnector(); + + public static void main(String[] args) throws Exception { + testWithObsoleteClassPathOption(null); + testWithObsoleteClassPathOption("someclasspath"); + } + + private static void testWithObsoleteClassPathOption(String obsoleteClassPath) throws Exception { + PathSearchingVirtualMachine vm = connector.launchVm("TestClass", makeClassPathOptions(obsoleteClassPath)); + List bootClassPath = vm.bootClassPath(); + Asserts.assertNotNull(bootClassPath, "Expected bootClassPath to be empty but was null"); + Asserts.assertEquals(0, bootClassPath.size(), "Expected bootClassPath.size() 0 but was: " + bootClassPath.size()); + } + + private static String makeClassPathOptions(String obsoleteClassPath) { + return obsoleteClassPath == null ? null : "-Dsun.boot.class.path=" + obsoleteClassPath; + } + +} diff --git a/jdk/test/com/sun/jdi/TestClass.java b/jdk/test/com/sun/jdi/TestClass.java new file mode 100644 index 00000000000..dab6b66648c --- /dev/null +++ b/jdk/test/com/sun/jdi/TestClass.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 TestClass { + + public static void main(String[] args) { + System.out.println("This is a test"); + } + +} From 8442a9192c70da2968024041eb747bda4d9d6893 Mon Sep 17 00:00:00 2001 From: Yuri Nesterenko Date: Wed, 6 Apr 2016 14:44:32 +0300 Subject: [PATCH 058/222] 8152693: Changed behavior of java/awt/xembed/server/TestXEmbedServerJava.java test Reviewed-by: ssadetsky, serb --- .../xembed/server/TestXEmbedServerJava.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/jdk/test/java/awt/xembed/server/TestXEmbedServerJava.java b/jdk/test/java/awt/xembed/server/TestXEmbedServerJava.java index 75898f4cbfe..8e0c3d6774e 100644 --- a/jdk/test/java/awt/xembed/server/TestXEmbedServerJava.java +++ b/jdk/test/java/awt/xembed/server/TestXEmbedServerJava.java @@ -76,7 +76,23 @@ public class TestXEmbedServerJava extends TestXEmbedServer { public Process startClient(Rectangle[] bounds, long window) { try { String java_home = System.getProperty("java.home"); - return Runtime.getRuntime().exec(java_home + "/bin/java -XaddExports:java.desktop/sun.awt.X11=ALL-UNNAMED JavaClient " + window); + boolean hasModules = true; + try { + Class.class.getMethod("getModule"); + }catch(Exception hasModulesEx) { + hasModules = false; + } + if (hasModules) { + System.out.println(java_home + + "/bin/java -XaddExports:java.desktop/sun.awt.X11=ALL-UNNAMED "+ + "-XaddExports:java.desktop/sun.awt=ALL-UNNAMED JavaClient " + window); + return Runtime.getRuntime().exec(java_home + + "/bin/java -XaddExports:java.desktop/sun.awt.X11=ALL-UNNAMED "+ + "-XaddExports:java.desktop/sun.awt=ALL-UNNAMED JavaClient " + window); + }else{ + System.out.println(java_home + "/bin/java JavaClient " + window); + return Runtime.getRuntime().exec(java_home + "/bin/java JavaClient " + window); + } } catch (IOException ex1) { ex1.printStackTrace(); } From 5621da5d8abe18945cb9f05f94d7e84834a6b5fc Mon Sep 17 00:00:00 2001 From: Peter Brunet Date: Wed, 6 Apr 2016 18:59:21 -0500 Subject: [PATCH 059/222] 8153149: Uninitialised memory in WinAccessBridge.cpp:1128 Remove extraneous initializer Reviewed-by: prr, serb --- .../windows/native/libwindowsaccessbridge/WinAccessBridge.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp index 45b47071fcd..3fa8fc6f67c 100644 --- a/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1125,7 +1125,7 @@ WinAccessBridge::getAccessibleContextWithFocus(HWND window, long *vmID, JOBJECT6 PrintDebugString("WinAccessBridge::getAccessibleContextWithFocus(%p, %X, )", window, vmID); // find vmID, etc. from HWND; ask that VM for the AC w/Focus - HWND pkgVMID = (HWND)ABLongToHandle( pkg->rVMID ) ; + HWND pkgVMID; if (getAccessibleContextFromHWND(window, (long *)&(pkgVMID), &(pkg->rAccessibleContext)) == TRUE) { HWND destABWindow = javaVMs->findAccessBridgeWindow((long)pkgVMID); // ineffecient [[[FIXME]]] if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { From da560b474474a5e760f193ae028785703951a6fe Mon Sep 17 00:00:00 2001 From: Peter Brunet Date: Wed, 6 Apr 2016 19:53:20 -0500 Subject: [PATCH 060/222] 8153153: Format string argument mismatch in jaccesswalker.cpp:545 Use proper format specifier Reviewed-by: prr, serb --- .../windows/native/jaccesswalker/jaccesswalker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp index b8602f52f0d..7943374892c 100644 --- a/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp +++ b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -543,7 +543,7 @@ void Jaccesswalker::addComponentNodes(long vmID, AccessibleContext context, } else { char s[LINE_BUFSIZE]; sprintf( s, - "ERROR calling GetAccessibleContextInfo; vmID = %X, context = %X", + "ERROR calling GetAccessibleContextInfo; vmID = %X, context = %p", vmID, context ); TVITEM tvi; From 24a9e0ac188a37dc57cc4d1bb8d8635abb4c4f89 Mon Sep 17 00:00:00 2001 From: Dmitry Fazunenko Date: Thu, 7 Apr 2016 17:43:35 +0400 Subject: [PATCH 061/222] 8152432: Implement setting jtreg @requires properties vm.flavor, vm.bits, vm.compMode Reviewed-by: iignatyev --- test/jtreg-ext/requires/VMProps.java | 136 +++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 test/jtreg-ext/requires/VMProps.java diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java new file mode 100644 index 00000000000..ef7de8faf39 --- /dev/null +++ b/test/jtreg-ext/requires/VMProps.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package requires; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * The Class to be invoked by jtreg prior Test Suite execution to + * collect information about VM. + * Properties set by this Class will be available in the @requires expressions. + */ +public class VMProps implements Callable> { + + /** + * Collects information about VM properties. + * This method will be invoked by jtreg. + * + * @return Map of property-value pairs. + */ + @Override + public Map call() { + Map map = new HashMap<>(); + map.put("vm.flavor", vmFlavor()); + map.put("vm.compMode", vmCompMode()); + map.put("vm.bits", vmBits()); + dump(map); + return map; + } + + /** + * @return VM type value extracted from the "java.vm.name" property. + */ + protected String vmFlavor() { + // E.g. "Java HotSpot(TM) 64-Bit Server VM" + String vmName = System.getProperty("java.vm.name"); + if (vmName == null) { + return null; + } + + Pattern startP = Pattern.compile(".* (\\S+) VM"); + Matcher m = startP.matcher(vmName); + if (m.matches()) { + return m.group(1).toLowerCase(); + } + return null; + } + + /** + * @return VM compilation mode extracted from the "java.vm.info" property. + */ + protected String vmCompMode() { + // E.g. "mixed mode" + String vmInfo = System.getProperty("java.vm.info"); + if (vmInfo == null) { + return null; + } + int k = vmInfo.toLowerCase().indexOf(" mode"); + if (k < 0) { + return null; + } + vmInfo = vmInfo.substring(0, k); + switch (vmInfo) { + case "mixed" : return "Xmixed"; + case "compiled" : return "Xcomp"; + case "interpreted" : return "Xint"; + default: return null; + } + } + + /** + * @return VM bitness, the value of the "sun.arch.data.model" property. + */ + protected String vmBits() { + return System.getProperty("sun.arch.data.model"); + } + + /** + * Dumps the map to the file if the file name is given as the property. + * This functionality could be helpful to know context in the real + * execution. + * + * @param map + */ + protected void dump(Map map) { + String dumpFileName = System.getProperty("vmprops.dump"); + if (dumpFileName == null) { + return; + } + List lines = new ArrayList<>(); + map.forEach((k,v) -> lines.add(k + ":" + v)); + try { + Files.write(Paths.get(dumpFileName), lines); + } catch (IOException e) { + throw new RuntimeException("Failed to dump properties into '" + + dumpFileName + "'", e); + } + } + + /** + * This method is for the testing purpose only. + * @param args + */ + public static void main(String args[]) { + Map map = new VMProps().call(); + map.forEach((k,v) -> System.out.println(k + ": '" + v + "'")); + } +} From 7aaf0feaf6c43ca6937ebe7f2be2971f2510b646 Mon Sep 17 00:00:00 2001 From: Nishit Jain Date: Fri, 8 Apr 2016 12:00:19 +0900 Subject: [PATCH 062/222] 7015696: The new currency symbols 20B9 (INDIAN RUPEE), 20BA (TURKISH LIRA), 20BD (RUBLE SIGN) not displayed 8031992: Add Kannada support to the JDK Reviewed-by: okutsu, peytoia --- jdk/make/data/fontconfig/windows.fontconfig.properties | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jdk/make/data/fontconfig/windows.fontconfig.properties b/jdk/make/data/fontconfig/windows.fontconfig.properties index 3a2e2b31b18..fcfcb8f5190 100644 --- a/jdk/make/data/fontconfig/windows.fontconfig.properties +++ b/jdk/make/data/fontconfig/windows.fontconfig.properties @@ -37,6 +37,7 @@ allfonts.chinese-gb18030-extb=SimSun-ExtB allfonts.chinese-hkscs=MingLiU_HKSCS allfonts.chinese-ms950-extb=MingLiU-ExtB allfonts.devanagari=Mangal +allfonts.kannada=Tunga allfonts.dingbats=Wingdings allfonts.lucida=Lucida Sans Regular allfonts.symbol=Symbol @@ -239,11 +240,11 @@ sequence.allfonts.x-windows-874=alphabetic,thai,dingbats,symbol sequence.fallback=lucida,symbols,\ chinese-ms950,chinese-hkscs,chinese-ms936,chinese-gb18030,\ - japanese,korean,chinese-ms950-extb,chinese-ms936-extb,georgian + japanese,korean,chinese-ms950-extb,chinese-ms936-extb,georgian,kannada # Exclusion Ranges -exclusion.alphabetic=0700-1e9f,1f00-2017,2020-20ab,20ad-f8ff +exclusion.alphabetic=0700-1e9f,1f00-2017,2020-20ab,20ad-20b8,20bb-20bc,20be-f8ff exclusion.chinese-gb18030=0390-03d6,2200-22ef,2701-27be exclusion.hebrew=0041-005a,0060-007a,007f-00ff,20ac-20ac @@ -295,6 +296,7 @@ filename.GulimChe=gulim.TTC filename.Lucida_Sans_Regular=LucidaSansRegular.ttf filename.Mangal=MANGAL.TTF +filename.Tunga=TUNGA.TTF filename.Symbol=SYMBOL.TTF filename.Wingdings=WINGDING.TTF From 540242ecef1ef17644dc2dae0d3210b69bd29892 Mon Sep 17 00:00:00 2001 From: Alexander Stepanov Date: Fri, 8 Apr 2016 12:56:28 +0300 Subject: [PATCH 063/222] 8152183: [TEST] add test for TIFFField Reviewed-by: prr, yan --- .../tiff/MultiPageImageTIFFFieldTest.java | 378 +++++++++++++ .../tiff/TIFFDirectoryWriteReadTest.java | 3 +- .../imageio/plugins/tiff/TIFFFieldTest.java | 502 ++++++++++++++++++ 3 files changed, 882 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java create mode 100644 jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java diff --git a/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java new file mode 100644 index 00000000000..4a5757824fd --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + * @ignore 8148454 + * @bug 8152183 8148454 + * @author a.stepanov + * @summary check that TIFFields are derived properly for multi-page tiff + * @run main MultiPageImageTIFFFieldTest + */ + +import java.awt.*; +import java.awt.color.*; +import java.awt.image.BufferedImage; +import java.io.*; +import javax.imageio.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.*; +import javax.imageio.plugins.tiff.*; + + +public class MultiPageImageTIFFFieldTest { + + private final static String FILENAME = "test.tiff"; + private final static int W1 = 20, H1 = 40, W2 = 100, H2 = 15; + private final static Color C1 = Color.BLACK, C2 = Color.RED; + + private final static int N_WIDTH = BaselineTIFFTagSet.TAG_IMAGE_WIDTH; + private final static int N_HEIGHT = BaselineTIFFTagSet.TAG_IMAGE_LENGTH; + + private static final String DESCRIPTION_1[] = {"Description-1", "abc ABC"}; + private static final String DESCRIPTION_2[] = {"Description-2", "1-2-3"}; + private final static int N_DESCRIPTION = + BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION; + + private final static String EXIF_DATA_1[] = {"2001:01:01 00:00:01"}; + private final static String EXIF_DATA_2[] = {"2002:02:02 00:00:02"}; + private final static int N_EXIF = ExifTIFFTagSet.TAG_DATE_TIME_ORIGINAL; + + private final static String GPS_DATA[] = { + ExifGPSTagSet.STATUS_MEASUREMENT_IN_PROGRESS}; + private final static int N_GPS = ExifGPSTagSet.TAG_GPS_STATUS; + + private final static short FAX_DATA = + FaxTIFFTagSet.CLEAN_FAX_DATA_ERRORS_UNCORRECTED; + private final static int N_FAX = FaxTIFFTagSet.TAG_CLEAN_FAX_DATA; + + private static final byte[] ICC_PROFILE_2 = + ICC_ProfileRGB.getInstance(ColorSpace.CS_sRGB).getData(); + private static final int N_ICC = BaselineTIFFTagSet.TAG_ICC_PROFILE; + + private static final int N_BPS = BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE; + + private static final int + COMPRESSION_1 = BaselineTIFFTagSet.COMPRESSION_DEFLATE, + COMPRESSION_2 = BaselineTIFFTagSet.COMPRESSION_LZW; + private static final int N_COMPRESSION = BaselineTIFFTagSet.TAG_COMPRESSION; + + private static final int + GRAY_1 = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO, + GRAY_2 = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO, + RGB = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB; + + private static final int N_PHOTO = + BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION; + + private ImageWriter getTIFFWriter() { + + java.util.Iterator writers = + ImageIO.getImageWritersByFormatName("TIFF"); + if (!writers.hasNext()) { + throw new RuntimeException("No writers available for TIFF format"); + } + return writers.next(); + } + + private ImageReader getTIFFReader() { + + java.util.Iterator readers = + ImageIO.getImageReadersByFormatName("TIFF"); + if (!readers.hasNext()) { + throw new RuntimeException("No readers available for TIFF format"); + } + return readers.next(); + } + + private void addASCIIField(TIFFDirectory d, + String name, + String data[], + int num) { + + d.addTIFFField(new TIFFField( + new TIFFTag(name, num, 1 << TIFFTag.TIFF_ASCII), + TIFFTag.TIFF_ASCII, data.length, data)); + } + + private void checkASCIIField(TIFFDirectory d, + String what, + String data[], + int num) { + + String notFound = what + " field was not found"; + check(d.containsTIFFField(num), notFound); + TIFFField f = d.getTIFFField(num); + check(f.getType() == TIFFTag.TIFF_ASCII, "field type != ASCII"); + check(f.getCount() == data.length, "invalid " + what + " data count"); + for (int i = 0; i < data.length; i++) { + check(f.getValueAsString(i).equals(data[i]), + "invalid " + what + " data"); + } + } + + private void writeImage() throws Exception { + + OutputStream s = new BufferedOutputStream(new FileOutputStream(FILENAME)); + try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) { + + ImageWriter writer = getTIFFWriter(); + writer.setOutput(ios); + + BufferedImage img1 = + new BufferedImage(W1, H1, BufferedImage.TYPE_BYTE_GRAY); + Graphics g = img1.getGraphics(); + g.setColor(C1); + g.fillRect(0, 0, W1, H1); + g.dispose(); + + BufferedImage img2 = + new BufferedImage(W2, H2, BufferedImage.TYPE_INT_RGB); + g = img2.getGraphics(); + g.setColor(C2); + g.fillRect(0, 0, W2, H2); + g.dispose(); + + ImageWriteParam param1 = writer.getDefaultWriteParam(); + param1.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param1.setCompressionType("Deflate"); + param1.setCompressionQuality(0.5f); + + ImageWriteParam param2 = writer.getDefaultWriteParam(); + param2.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param2.setCompressionType("LZW"); + param2.setCompressionQuality(0.5f); + + IIOMetadata + md1 = writer.getDefaultImageMetadata( + new ImageTypeSpecifier(img1), param1), + md2 = writer.getDefaultImageMetadata( + new ImageTypeSpecifier(img2), param2); + + TIFFDirectory + dir1 = TIFFDirectory.createFromMetadata(md1), + dir2 = TIFFDirectory.createFromMetadata(md2); + + addASCIIField(dir1, "ImageDescription", DESCRIPTION_1, N_DESCRIPTION); + addASCIIField(dir2, "ImageDescription", DESCRIPTION_2, N_DESCRIPTION); + + addASCIIField(dir1, "GPSStatus", GPS_DATA, N_GPS); + addASCIIField(dir2, "GPSStatus", GPS_DATA, N_GPS); + + addASCIIField(dir1, "DateTimeOriginal", EXIF_DATA_1, N_EXIF); + addASCIIField(dir2, "DateTimeOriginal", EXIF_DATA_2, N_EXIF); + + TIFFTag faxTag = new TIFFTag( + "CleanFaxData", N_FAX, 1 << TIFFTag.TIFF_SHORT); + dir1.addTIFFField(new TIFFField(faxTag, FAX_DATA)); + dir2.addTIFFField(new TIFFField(faxTag, FAX_DATA)); + + dir2.addTIFFField(new TIFFField( + new TIFFTag("ICC Profile", N_ICC, 1 << TIFFTag.TIFF_UNDEFINED), + TIFFTag.TIFF_UNDEFINED, ICC_PROFILE_2.length, ICC_PROFILE_2)); + + writer.prepareWriteSequence(null); + writer.writeToSequence( + new IIOImage(img1, null, dir1.getAsMetadata()), param1); + writer.writeToSequence( + new IIOImage(img2, null, dir2.getAsMetadata()), param2); + writer.endWriteSequence(); + + ios.flush(); + writer.dispose(); + } + s.close(); + } + + private void checkBufferedImages(BufferedImage im1, BufferedImage im2) { + + check(im1.getWidth() == W1, "invalid width for image 1"); + check(im1.getHeight() == H1, "invalid height for image 1"); + check(im2.getWidth() == W2, "invalid width for image 2"); + check(im2.getHeight() == H2, "invalid height for image 2"); + + Color + c1 = new Color(im1.getRGB(W1 / 2, H1 / 2)), + c2 = new Color(im2.getRGB(W2 / 2, H2 / 2)); + + check(c1.equals(C1), "invalid image 1 color"); + check(c2.equals(C2), "invalid image 2 color"); + } + + private void readAndCheckImage() throws Exception { + + ImageReader reader = getTIFFReader(); + + ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME)); + reader.setInput(s, false, true); + + int ni = reader.getNumImages(true); + check(ni == 2, "invalid number of images"); + + // check TIFFImageReadParam for multipage image + TIFFImageReadParam + param1 = new TIFFImageReadParam(), param2 = new TIFFImageReadParam(); + + param1.addAllowedTagSet(ExifTIFFTagSet.getInstance()); + param1.addAllowedTagSet(ExifGPSTagSet.getInstance()); + + param2.addAllowedTagSet(ExifTIFFTagSet.getInstance()); + param2.addAllowedTagSet(GeoTIFFTagSet.getInstance()); + + // FaxTIFFTagSet is allowed by default + param2.removeAllowedTagSet(FaxTIFFTagSet.getInstance()); + + + // read images and metadata + IIOImage i1 = reader.readAll(0, param1), i2 = reader.readAll(1, param2); + BufferedImage + bi1 = (BufferedImage) i1.getRenderedImage(), + bi2 = (BufferedImage) i2.getRenderedImage(); + + // check rendered images, just in case + checkBufferedImages(bi1, bi2); + + TIFFDirectory + dir1 = TIFFDirectory.createFromMetadata(i1.getMetadata()), + dir2 = TIFFDirectory.createFromMetadata(i2.getMetadata()); + + // check ASCII fields + checkASCIIField( + dir1, "image 1 description", DESCRIPTION_1, N_DESCRIPTION); + checkASCIIField( + dir2, "image 2 description", DESCRIPTION_2, N_DESCRIPTION); + + checkASCIIField(dir1, "image 1 datetime", EXIF_DATA_1, N_EXIF); + checkASCIIField(dir2, "image 2 datetime", EXIF_DATA_2, N_EXIF); + + // check sizes + TIFFField f = dir1.getTIFFField(N_WIDTH); + check((f.getCount() == 1) && (f.getAsInt(0) == W1), + "invalid width field for image 1"); + f = dir2.getTIFFField(N_WIDTH); + check((f.getCount() == 1) && (f.getAsInt(0) == W2), + "invalid width field for image 2"); + + f = dir1.getTIFFField(N_HEIGHT); + check((f.getCount() == 1) && (f.getAsInt(0) == H1), + "invalid height field for image 1"); + f = dir2.getTIFFField(N_HEIGHT); + check((f.getCount() == 1) && (f.getAsInt(0) == H2), + "invalid height field for image 2"); + + // check fax data + check(dir1.containsTIFFField(N_FAX), "image 2 TIFF directory " + + "must contain clean fax data"); + f = dir1.getTIFFField(N_FAX); + check( + (f.getCount() == 1) && f.isIntegral() && (f.getAsInt(0) == FAX_DATA), + "invalid clean fax data"); + + check(!dir2.containsTIFFField(N_FAX), "image 2 TIFF directory " + + "must not contain fax fields"); + + // check GPS data + checkASCIIField(dir1, "GPS status", GPS_DATA, N_GPS); + + check(!dir2.containsTIFFField(N_GPS), "image 2 TIFF directory " + + "must not contain GPS fields"); + + // check ICC profile data + check(!dir1.containsTIFFField(N_ICC), "image 1 TIFF directory " + + "must not contain ICC Profile field"); + check(dir2.containsTIFFField(N_ICC), "image 2 TIFF directory " + + "must contain ICC Profile field"); + + f = dir2.getTIFFField(N_ICC); + check(f.getType() == TIFFTag.TIFF_UNDEFINED, + "invalid ICC profile field type"); + int cnt = f.getCount(); + byte icc[] = f.getAsBytes(); + check((cnt == ICC_PROFILE_2.length) && (cnt == icc.length), + "invalid ICC profile"); + for (int i = 0; i < cnt; i++) { + check(icc[i] == ICC_PROFILE_2[i], "invalid ICC profile data"); + } + + // check component sizes + check(dir1.getTIFFField(N_BPS).isIntegral() && + dir2.getTIFFField(N_BPS).isIntegral(), + "invalid bits per sample type"); + int sz1[] = bi1.getColorModel().getComponentSize(), + sz2[] = bi2.getColorModel().getComponentSize(), + bps1[] = dir1.getTIFFField(N_BPS).getAsInts(), + bps2[] = dir2.getTIFFField(N_BPS).getAsInts(); + + check((bps1.length == sz1.length) && (bps2.length == sz2.length), + "invalid component size count"); + + for (int i = 0; i < bps1.length; i++) { + check(bps1[i] == sz1[i], "image 1: invalid bits per sample data"); + } + + for (int i = 0; i < bps2.length; i++) { + check(bps2[i] == sz2[i], "image 2: invalid bits per sample data"); + } + + // check compression data + check(dir1.containsTIFFField(N_COMPRESSION) && + dir2.containsTIFFField(N_COMPRESSION), + "compression info lost"); + f = dir1.getTIFFField(N_COMPRESSION); + check(f.isIntegral() && (f.getCount() == 1) && + (f.getAsInt(0) == COMPRESSION_1), "invalid image 1 compression data"); + + f = dir2.getTIFFField(N_COMPRESSION); + check(f.isIntegral() && (f.getCount() == 1) && + (f.getAsInt(0) == COMPRESSION_2), "invalid image 2 compression data"); + + // check photometric interpretation + f = dir1.getTIFFField(N_PHOTO); + check(f.isIntegral() && (f.getCount() == 1) && + ((f.getAsInt(0) == GRAY_1) || (f.getAsInt(0) == GRAY_2)), + "invalid photometric interpretation for image 1"); + + f = dir2.getTIFFField(N_PHOTO); + check(f.isIntegral() && (f.getCount() == 1) && (f.getAsInt(0) == RGB), + "invalid photometric interpretation for image 2"); + } + + public void run() { + + try { + writeImage(); + readAndCheckImage(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void check(boolean ok, String msg) { + + if (!ok) { throw new RuntimeException(msg); } + } + + public static void main(String[] args) { + (new MultiPageImageTIFFFieldTest()).run(); + } +} diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java index eb668255ea6..45477608016 100644 --- a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java @@ -207,7 +207,8 @@ public class TIFFDirectoryWriteReadTest { // RGB: PhotometricInterpretation = 2 f = dir.getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); check(f.getCount() == 1, "invalid count"); - check(f.getAsInt(0) == 2, "invalid photometric interpretation for RGB"); + check(f.getAsInt(0) == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB, + "invalid photometric interpretation value"); String rat = " resolution must be rational"; f = dir.getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION); diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java new file mode 100644 index 00000000000..a50929e8a46 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8152183 + * @author a.stepanov + * @summary Some checks for TIFFField methods + * @run main TIFFFieldTest + */ + +import java.util.List; +import java.util.ArrayList; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.plugins.tiff.*; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public class TIFFFieldTest { + + private final static String NAME = "tag"; // tag name + private final static int NUM = 12345; // tag number + private final static int MIN_TYPE = TIFFTag.MIN_DATATYPE; + private final static int MAX_TYPE = TIFFTag.MAX_DATATYPE; + private final static String CONSTRUCT = "can construct TIFFField with "; + + private void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + private void testConstructors() { + + // test constructors + + TIFFTag tag = new TIFFTag( + NAME, NUM, 1 << TIFFTag.TIFF_SHORT | 1 << TIFFTag.TIFF_LONG); + TIFFField f; + + // constructor: TIFFField(tag, value) + boolean ok = false; + try { new TIFFField(null, 0); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, -1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid count"); + + // check value type recognition + int v = 1 << 16; + f = new TIFFField(tag, v - 1); + check(f.getType() == TIFFTag.TIFF_SHORT, "must be treated as short"); + check(f.isIntegral(), "must be integral"); + f = new TIFFField(tag, v); + check(f.getType() == TIFFTag.TIFF_LONG, "must be treated as long"); + + // other checks + check(f.getAsLongs().length == 1, "invalid long[] size"); + check(f.isIntegral(), "must be integral"); + check((f.getDirectory() == null) && !f.hasDirectory(), + "must not have directory"); + check(f.getValueAsString(0).equals(String.valueOf(v)), + "invalid string representation of value"); + check(f.getTag().getNumber() == f.getTagNumber(), + "invalid tag number"); + check(f.getCount() == 1, "invalid count"); + check(f.getTagNumber() == NUM, "invalid tag number"); + + // constructor: TIFFField(tag, type, count) + int type = TIFFTag.TIFF_SHORT; + + ok = false; + try { new TIFFField(null, type, 1); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, MAX_TYPE + 1, 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid type tag"); + + // check that count == 1 for TIFF_IFD_POINTER + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 0); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "only count = 1 should be allowed for IFDPointer"); + + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 2); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "only count = 1 should be allowed for IFDPointer"); + + // check that count == 0 is not allowed for TIFF_RATIONAL, TIFF_SRATIONAL + // (see fix for JDK-8149120) + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_RATIONAL, 0); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "count = 0 should not be allowed for Rational"); + + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_SRATIONAL, 0); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "count = 0 should not be allowed for SRational"); + + ok = false; + try { new TIFFField(tag, type, -1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "with invalid data count"); + + f = new TIFFField(tag, type, 0); + check(f.getCount() == 0, "invalid count"); + check(!f.hasDirectory(), "must not have directory"); + + // constructor: TIFFField(tag, type, count, data) + double a[] = {0.1, 0.2, 0.3}; + ok = false; + try { new TIFFField(null, TIFFTag.TIFF_DOUBLE, a.length, a); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, type, a.length - 1, a); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid data count"); + + String a2[] = {"one", "two"}; + ok = false; + try { new TIFFField(tag, type, 2, a2); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid data type"); + check((f.getDirectory() == null) && !f.hasDirectory(), + "must not have directory"); + + // constructor: TIFFField(tag, type, offset, dir) + List tags = new ArrayList<>(); + tags.add(tag); + TIFFTagSet sets[] = {new TIFFTagSet(tags)}; + TIFFDirectory dir = new TIFFDirectory(sets, null); + + ok = false; + try { new TIFFField(null, type, 4L, dir); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, type, 0L, dir); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "non-positive offset"); + + long offset = 4; + + for (int t = MIN_TYPE; t <= MAX_TYPE; t++) { + + tag = new TIFFTag(NAME, NUM, 1 << t); + + // only TIFF_LONG and TIFF_IFD_POINTER types are allowed + if (t == TIFFTag.TIFF_LONG || t == TIFFTag.TIFF_IFD_POINTER) { + + f = new TIFFField(tag, t, offset, dir); + check(f.hasDirectory(), "must have directory"); + + check(f.getDirectory().getTag(NUM).getName().equals(NAME), + "invalid tag name"); + + check(f.getCount() == 1, "invalid count"); + check(f.getAsLong(0) == offset, "invalid offset"); + } else { + ok = false; + try { new TIFFField(tag, t, offset, dir); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid data type"); + } + } + + type = TIFFTag.TIFF_IFD_POINTER; + tag = new TIFFTag(NAME, NUM, 1 << type); + ok = false; + try { new TIFFField(tag, type, offset, null); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null TIFFDirectory"); + + type = TIFFTag.TIFF_LONG; + tag = new TIFFTag(NAME, NUM, 1 << type); + ok = false; + try { new TIFFField(tag, type, offset, null); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null TIFFDirectory"); + } + + private void testTypes() { + + // test getTypeName(), getTypeByName() methods + + boolean ok = false; + try { TIFFField.getTypeName(MIN_TYPE - 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "invalid data type number used"); + + ok = false; + try { TIFFField.getTypeName(MAX_TYPE + 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "invalid data type number used"); + + for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { + String name = TIFFField.getTypeName(type); + check(TIFFField.getTypeByName(name) == type, "invalid type"); + } + + for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { + + TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); + TIFFField f = new TIFFField(tag, type, 1); + check(f.getType() == type, "invalid type"); + + // check that invalid data types can not be used + for (int type2 = MIN_TYPE; type2 <= MAX_TYPE; ++type2) { + if (type2 != type) { + ok = false; + try { new TIFFField(tag, type2, 1); } // invalid type + catch (IllegalArgumentException e) { ok = true; } + check(ok, "invalid type was successfully set"); + } + } + } + } + + private void testGetAs() { + + // test getAs...() methods + + int type = TIFFTag.TIFF_SHORT; + TIFFTag tag = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT); + + short v = 123; + TIFFField f = new TIFFField(tag, v); + + check(f.getAsInt(0) == (int) v, "invalid int value"); + check(f.getAsLong(0) == (long) v, "invalid long value"); + check(f.getAsFloat(0) == (float) v, "invalid float value"); + check(f.getAsDouble(0) == (double) v, "invalid double value"); + check(f.getValueAsString(0).equals(Short.toString(v)), + "invalid string representation"); + + check(f.getAsInts().length == 1, "inavlid array size"); + check((int) v == f.getAsInts()[0], "invalid int value"); + + float fa[] = {0.01f, 1.01f}; + type = TIFFTag.TIFF_FLOAT; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, fa.length, fa); + check(f.getCount() == fa.length, "invalid count"); + float fa2[] = f.getAsFloats(); + check(fa2.length == fa.length, "invalid array size"); + + for (int i = 0; i < fa.length; i++) { + check(fa2[i] == fa[i], "invalid value"); + check(f.getAsDouble(i) == fa[i], "invalid value"); + check(f.getAsInt(i) == (int) fa[i], "invalid value"); // cast to int + check(f.getValueAsString(i).equals(Float.toString(fa[i])), + "invalid string representation"); + } + + byte ba[] = {-1, -10, -100}; + type = TIFFTag.TIFF_BYTE; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, ba.length, ba); + check(f.getCount() == ba.length, "invalid count"); + byte ba2[] = f.getAsBytes(); + check(ba2.length == ba.length, "invalid count"); + + for (int i = 0; i < ba.length; i++) { + check(ba[i] == ba2[i], "invalid value"); + check(ba[i] == (byte) f.getAsDouble(i), "invalid value"); + check(ba[i] == (byte) f.getAsLong(i), "invalid value"); + + int unsigned = ba[i] & 0xff; + check(f.getAsInt(i) == unsigned, "must be treated as unsigned"); + } + + char ca[] = {'a', 'z', 0xffff}; + type = TIFFTag.TIFF_SHORT; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, ca.length, ca); + check(f.getCount() == ca.length, "invalid count"); + char ca2[] = f.getAsChars(); + check(ba2.length == ba.length, "invalid count"); + + for (int i = 0; i < ca.length; i++) { + check(ca[i] == ca2[i], "invalid value"); + check(ca[i] == (char) f.getAsDouble(i), "invalid value"); + check(ca[i] == (char) f.getAsLong(i), "invalid value"); + check(ca[i] == (char) f.getAsInt(i), "invalid value"); + } + + type = TIFFTag.TIFF_DOUBLE; + double da[] = {0.1, 0.2, 0.3}; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, da.length, da); + check(!f.isIntegral(), "isIntegral must be false"); + + double da2[] = f.getAsDoubles(); + check(f.getData() instanceof double[], "invalid data type"); + double da3[] = (double[]) f.getData(); + check((da.length == da2.length) && + (da.length == da2.length) && + (da.length == f.getCount()), + "invalid data count"); + for (int i = 0; i < da.length; ++i) { + check(da[i] == da2[i], "invalid data"); + check(da[i] == da3[i], "invalid data"); + } + + boolean ok = false; + try { f.getAsShorts(); } + catch (ClassCastException e) { ok = true; } + check(ok, "invalid data cast"); + + ok = false; + try { f.getAsRationals(); } + catch (ClassCastException e) { ok = true; } + check(ok, "invalid data cast"); + + ok = false; + try { TIFFField.createArrayForType(TIFFTag.MIN_DATATYPE - 1, 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "can create array with invalid datatype"); + + ok = false; + try { TIFFField.createArrayForType(TIFFTag.MAX_DATATYPE + 1, 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "can create array with invalid datatype"); + + ok = false; + try { TIFFField.createArrayForType(TIFFTag.TIFF_FLOAT, -1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "can create array with negative count"); + + int n = 3; + Object + RA = TIFFField.createArrayForType(TIFFTag.TIFF_RATIONAL, n), + SRA = TIFFField.createArrayForType(TIFFTag.TIFF_SRATIONAL, n); + check(RA instanceof long[][], "invalid data type"); + check(SRA instanceof int[][], "invalid data type"); + + long ra[][] = (long[][]) RA; + int sra[][] = (int[][]) SRA; + check((ra.length == n) && (sra.length == n), "invalid data size"); + for (int i = 0; i < n; i++) { + check((ra[i].length == 2) && (sra[i].length == 2), + "invalid data size"); + ra[i][0] = 1; ra[i][1] = 5 + i; + sra[i][0] = -1; sra[i][1] = 5 + i; + } + + type = TIFFTag.TIFF_RATIONAL; + TIFFField f1 = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, n, ra); + type = TIFFTag.TIFF_SRATIONAL; + TIFFField f2 = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, n, sra); + + check((f1.getCount() == ra.length) && (f2.getCount() == sra.length), + "invalid data count"); + + check(f1.getAsRationals().length == n, "invalid data count"); + check(f2.getAsSRationals().length == n, "invalid data count"); + for (int i = 0; i < n; i++) { + long r[] = f1.getAsRational(i); + check(r.length == 2, "invalid data format"); + check((r[0] == 1) && (r[1] == i + 5), "invalid data"); + + int sr[] = f2.getAsSRational(i); + check(sr.length == 2, "invalid data format"); + check((sr[0] == -1) && (sr[1] == i + 5), "invalid data"); + + // check string representation + String s = Long.toString(r[0]) + "/" + Long.toString(r[1]); + check(s.equals(f1.getValueAsString(i)), + "invalid string representation"); + + s = Integer.toString(sr[0]) + "/" + Integer.toString(sr[1]); + check(s.equals(f2.getValueAsString(i)), + "invalid string representation"); + + // see the documentation for getAsInt: + // TIFF_SRATIONAL or TIFF_RATIONAL format are evaluated + // by dividing the numerator into the denominator using + // double-precision arithmetic and then casting to int + check(f1.getAsInt(i) == (int)(r[0] / r[1]), + "invalid result for getAsInt"); + check(f2.getAsInt(i) == (int)(r[0] / r[1]), + "invalid result for getAsInt"); + } + + ok = false; + try { f1.getAsRational(ra.length); } + catch (ArrayIndexOutOfBoundsException e) { ok = true; } + check(ok, "invalid index"); + + String sa[] = {"-1.e-25", "22", "-1.23E5"}; + type = TIFFTag.TIFF_ASCII; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, sa.length, sa); + + // test clone() method + TIFFField cloned = null; + try { cloned = f.clone(); } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + + check(f.getCount() == cloned.getCount(), "invalid cloned field count"); + + check(f.getCount() == sa.length, "invalid data count"); + for (int i = 0; i < sa.length; i++) { + check(sa[i].equals(f.getAsString(i)), "invalid data"); + // see docs: "data in TIFF_ASCII format will be parsed as by + // the Double.parseDouble method, with the result cast to int" + check(f.getAsInt(i) == + (int) Double.parseDouble(sa[i]), "invalid data"); + check(f.getAsDouble(i) == Double.parseDouble(sa[i]), "invalid data"); + + check(sa[i].equals(cloned.getAsString(i)), "invalid cloned data"); + } + } + + private void testCreateFromNode() { + + int type = TIFFTag.TIFF_LONG; + + List tags = new ArrayList<>(); + int v = 1234567; + TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); + tags.add(tag); + TIFFTagSet ts = new TIFFTagSet(tags); + + boolean ok = false; + try { TIFFField.createFromMetadataNode(ts, null); } + catch (NullPointerException e) { ok = true; } + check(ok, "can create TIFFField from a null node"); + + TIFFField f = new TIFFField(tag, v); + Node node = f.getAsNativeNode(); + check(node.getNodeName().equals(f.getClass().getSimpleName()), + "invalid node name"); + + NamedNodeMap attrs = node.getAttributes(); + for (int i = 0; i < attrs.getLength(); i++) { + String an = attrs.item(i).getNodeName().toLowerCase(); + String av = attrs.item(i).getNodeValue(); + if (an.contains("name")) { + check(av.equals(NAME), "invalid tag name"); + } else if (an.contains("number")) { + check(av.equals(Integer.toString(NUM)), "invalid tag number"); + } + } + + // invalid node + IIOMetadataNode nok = new IIOMetadataNode("NOK"); + + ok = false; + try { TIFFField.createFromMetadataNode(ts, nok); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid node name"); + + TIFFField f2 = TIFFField.createFromMetadataNode(ts, node); + check(f2.getType() == type, "invalid type"); + check(f2.getTagNumber() == NUM, "invalid tag number"); + check(f2.getTag().getName().equals(NAME), "invalid tag name"); + check(f2.getCount() == 1, "invalid count"); + check(f2.getAsInt(0) == v, "invalid value"); + } + + public static void main(String[] args) { + + TIFFFieldTest test = new TIFFFieldTest(); + test.testConstructors(); + test.testCreateFromNode(); + test.testTypes(); + test.testGetAs(); + } +} From fd6a72271b19efd83d54d758cdae294a70e87c2c Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 8 Apr 2016 13:14:23 +0200 Subject: [PATCH 064/222] 8152666: The new Hotspot Build System Co-authored-by: Magnus Ihse Bursie Co-authored-by: Ingemar Aberg Reviewed-by: ihse, dcubed, erikj --- jdk/make/Import.gmk | 8 ++++---- jdk/make/copy/Copy-java.base.gmk | 22 +++++++++++----------- jdk/make/lib/CoreLibraries.gmk | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/jdk/make/Import.gmk b/jdk/make/Import.gmk index 42155494fb2..d479b095514 100644 --- a/jdk/make/Import.gmk +++ b/jdk/make/Import.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -83,20 +83,20 @@ ifneq ($(STATIC_BUILD), true) endif ifneq ($(OPENJDK_TARGET_OS), windows) - ifeq ($(JVM_VARIANT_SERVER), true) + ifeq ($(call check-jvm-variant, server), true) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX) ifneq (, $(JSIG_DEBUGINFO)) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I)) endif endif - ifeq ($(JVM_VARIANT_CLIENT), true) + ifeq ($(call check-jvm-variant, client), true) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX) ifneq (, $(JSIG_DEBUGINFO)) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I)) endif endif ifneq ($(OPENJDK_TARGET_OS), macosx) - ifeq ($(JVM_VARIANT_MINIMAL1), true) + ifeq ($(call check-jvm-variant, minimal), true) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX) ifneq (,$(JSIG_DEBUGINFO)) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I)) diff --git a/jdk/make/copy/Copy-java.base.gmk b/jdk/make/copy/Copy-java.base.gmk index 04988de5f85..d50b52378f9 100644 --- a/jdk/make/copy/Copy-java.base.gmk +++ b/jdk/make/copy/Copy-java.base.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -88,7 +88,7 @@ endif # # How to install jvm.cfg. # -ifeq ($(JVM_VARIANT_ZERO), true) +ifeq ($(call check-jvm-variant, zero zeroshark), true) JVMCFG_ARCH := zero else JVMCFG_ARCH := $(OPENJDK_TARGET_CPU_LEGACY) @@ -99,7 +99,7 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) else JVMCFG_SRC := $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/conf/$(JVMCFG_ARCH)/jvm.cfg # Allow override by ALT_JVMCFG_SRC if it exists - JVMCFG_SRC := $(if $(wildcard $(ALT_JVMCFG_SRC)),$(ALT_JVMCFG_SRC),$(JVMCFG_SRC)) + JVMCFG_SRC := $(if $(wildcard $(ALT_JVMCFG_SRC)),$(ALT_JVMCFG_SRC),$(JVMCFG_SRC)) endif JVMCFG_DIR := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR) JVMCFG := $(JVMCFG_DIR)/jvm.cfg @@ -117,12 +117,12 @@ else # The main problem is deciding whether to use aliases for the VMs that are not # present and the current position is that we add aliases for client and server, but # not for minimal. - CLIENT_AND_SERVER := $(and $(findstring true, $(JVM_VARIANT_SERVER)), $(findstring true, $(JVM_VARIANT_CLIENT))) - ifeq ($(CLIENT_AND_SERVER), true) + CLIENT_AND_SERVER := $(call check-jvm-variant, client)+$(call check-jvm-variant, server) + ifeq ($(CLIENT_AND_SERVER), true+true) COPY_JVM_CFG_FILE := true else # For zero, the default jvm.cfg file is sufficient - ifeq ($(JVM_VARIANT_ZERO), true) + ifeq ($(call check-jvm-variant, zero zeroshark), true) COPY_JVM_CFG_FILE := true endif endif @@ -136,21 +136,21 @@ else $(MKDIR) -p $(@D) $(RM) $(@) # Now check for other permutations - ifeq ($(JVM_VARIANT_SERVER), true) + ifeq ($(call check-jvm-variant, server), true) $(PRINTF) "-server KNOWN\n">>$(@) $(PRINTF) "-client ALIASED_TO -server\n">>$(@) - ifeq ($(JVM_VARIANT_MINIMAL1), true) + ifeq ($(call check-jvm-variant, minimal), true) $(PRINTF) "-minimal KNOWN\n">>$(@) endif else - ifeq ($(JVM_VARIANT_CLIENT), true) + ifeq ($(call check-jvm-variant, client), true) $(PRINTF) "-client KNOWN\n">>$(@) $(PRINTF) "-server ALIASED_TO -client\n">>$(@) - ifeq ($(JVM_VARIANT_MINIMAL1), true) + ifeq ($(call check-jvm-variant, minimal), true) $(PRINTF) "-minimal KNOWN\n">>$(@) endif else - ifeq ($(JVM_VARIANT_MINIMAL1), true) + ifeq ($(call check-jvm-variant, minimal), true) $(PRINTF) "-minimal KNOWN\n">>$(@) $(PRINTF) "-server ALIASED_TO -minimal\n">>$(@) $(PRINTF) "-client ALIASED_TO -minimal\n">>$(@) diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk index f114c9b7d33..bccf46bb824 100644 --- a/jdk/make/lib/CoreLibraries.gmk +++ b/jdk/make/lib/CoreLibraries.gmk @@ -289,7 +289,7 @@ LIBJLI_SRC_DIRS := $(call FindSrcDirsForLib, java.base, jli) LIBJLI_CFLAGS := $(CFLAGS_JDKLIB) -ifeq ($(JVM_VARIANT_ZERO), true) +ifeq ($(call check-jvm-variant, zero zeroshark), true) ERGO_FAMILY := zero else ifeq ($(OPENJDK_TARGET_CPU_ARCH), x86) From e709aa268df64b2dc000433a1d9621a2fb0940f0 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 8 Apr 2016 13:14:23 +0200 Subject: [PATCH 065/222] 8152666: The new Hotspot Build System Co-authored-by: Magnus Ihse Bursie Co-authored-by: Ingemar Aberg Reviewed-by: ihse, dcubed, erikj --- common/autoconf/basics.m4 | 7 +- common/autoconf/build-performance.m4 | 3 + common/autoconf/buildjdk-spec.gmk.in | 11 + common/autoconf/compare.sh.in | 1 + common/autoconf/configure | 2 +- common/autoconf/configure.ac | 14 +- common/autoconf/flags.m4 | 860 +++++--- common/autoconf/generated-configure.sh | 2630 ++++++++++++++++++++---- common/autoconf/help.m4 | 13 +- common/autoconf/hotspot-spec.gmk.in | 13 +- common/autoconf/hotspot.m4 | 491 +++-- common/autoconf/jdk-options.m4 | 30 +- common/autoconf/jdk-version.m4 | 1 + common/autoconf/lib-std.m4 | 16 +- common/autoconf/libraries.m4 | 4 +- common/autoconf/platform.m4 | 245 +-- common/autoconf/spec.gmk.in | 74 +- common/autoconf/toolchain.m4 | 11 + common/autoconf/version-numbers | 1 + common/bin/compare.sh | 52 +- common/bin/compare_exceptions.sh.incl | 122 +- common/conf/jib-profiles.js | 8 +- make/Jprt.gmk | 21 +- make/Main.gmk | 13 +- make/common/MakeBase.gmk | 12 +- make/common/NativeCompilation.gmk | 141 +- make/jprt.properties | 8 +- 27 files changed, 3729 insertions(+), 1075 deletions(-) diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index 753d170beb2..f295a46d3c4 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -749,8 +749,8 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], BASIC_PREPEND_TO_PATH([PATH],$EXTRA_PATH) if test "x$OPENJDK_BUILD_OS" = "xsolaris"; then - # Add extra search paths on solaris for utilities like ar and as etc... - PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin" + # Add extra search paths on solaris for utilities like ar, as, dtrace etc... + PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin:/usr/sbin" fi AC_MSG_CHECKING([for sysroot]) @@ -777,7 +777,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR], # Create a default ./build/target-variant-debuglevel output root. if test "x${CONF_NAME}" = x; then AC_MSG_RESULT([in default location]) - CONF_NAME="${OPENJDK_TARGET_OS}-${OPENJDK_TARGET_CPU}-${JDK_VARIANT}-${ANDED_JVM_VARIANTS}-${DEBUG_LEVEL}" + CONF_NAME="${OPENJDK_TARGET_OS}-${OPENJDK_TARGET_CPU}-${JDK_VARIANT}-${JVM_VARIANTS_WITH_AND}-${DEBUG_LEVEL}" else AC_MSG_RESULT([in build directory with custom name]) fi @@ -1037,6 +1037,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS], BASIC_PATH_PROGS(HG, hg) BASIC_PATH_PROGS(STAT, stat) BASIC_PATH_PROGS(TIME, time) + BASIC_PATH_PROGS(DTRACE, dtrace) BASIC_PATH_PROGS(PATCH, [gpatch patch]) # Check if it's GNU time IS_GNU_TIME=`$TIME --version 2>&1 | $GREP 'GNU time'` diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4 index a3c69e02d08..0de3a9ee7f8 100644 --- a/common/autoconf/build-performance.m4 +++ b/common/autoconf/build-performance.m4 @@ -364,6 +364,9 @@ AC_DEFUN_ONCE([BPERF_SETUP_PRECOMPILED_HEADERS], elif test "x$ICECC" != "x"; then AC_MSG_RESULT([no, does not work effectively with icecc]) USE_PRECOMPILED_HEADER=0 + elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then + AC_MSG_RESULT([no, does not work with Solaris Studio]) + USE_PRECOMPILED_HEADER=0 else AC_MSG_RESULT([yes]) fi diff --git a/common/autoconf/buildjdk-spec.gmk.in b/common/autoconf/buildjdk-spec.gmk.in index f92602edc34..89167a388fb 100644 --- a/common/autoconf/buildjdk-spec.gmk.in +++ b/common/autoconf/buildjdk-spec.gmk.in @@ -57,6 +57,12 @@ OPENJDK_TARGET_CPU_BITS := @OPENJDK_BUILD_CPU_BITS@ OPENJDK_TARGET_CPU_ENDIAN := @OPENJDK_BUILD_CPU_ENDIAN@ OPENJDK_TARGET_CPU_LEGACY := @OPENJDK_BUILD_CPU_LEGACY@ +HOTSPOT_TARGET_OS := @HOTSPOT_BUILD_OS@ +HOTSPOT_TARGET_OS_TYPE := @HOTSPOT_BUILD_OS_TYPE@ +HOTSPOT_TARGET_CPU := @HOTSPOT_BUILD_CPU@ +HOTSPOT_TARGET_CPU_ARCH := @HOTSPOT_BUILD_CPU_ARCH@ +HOTSPOT_TARGET_CPU_DEFINE := @HOTSPOT_BUILD_CPU_DEFINE@ + CFLAGS_JDKLIB := @OPENJDK_BUILD_CFLAGS_JDKLIB@ CXXFLAGS_JDKLIB := @OPENJDK_BUILD_CXXFLAGS_JDKLIB@ LDFLAGS_JDKLIB := @OPENJDK_BUILD_LDFLAGS_JDKLIB@ @@ -65,6 +71,11 @@ CXXFLAGS_JDKEXE := @OPENJDK_BUILD_CXXFLAGS_JDKEXE@ LDFLAGS_JDKEXE := @OPENJDK_BUILD_LDFLAGS_JDKEXE@ OPENJDK_TARGET_CPU_JLI_CFLAGS := @OPENJDK_BUILD_CPU_JLI_CFLAGS@ +JVM_CFLAGS := @OPENJDK_BUILD_JVM_CFLAGS@ +JVM_LDFLAGS := @OPENJDK_BUILD_JVM_LDFLAGS@ +JVM_ASFLAGS := @OPENJDK_BUILD_JVM_ASFLAGS@ +JVM_LIBS := @OPENJDK_BUILD_JVM_LIBS@ + # The compiler for the build platform is likely not warning compatible with the official # compiler. WARNINGS_AS_ERRORS := false diff --git a/common/autoconf/compare.sh.in b/common/autoconf/compare.sh.in index f8f97ec02d2..e03ff07387c 100644 --- a/common/autoconf/compare.sh.in +++ b/common/autoconf/compare.sh.in @@ -34,6 +34,7 @@ export LEGACY_BUILD_DIR=@OPENJDK_TARGET_OS@-@OPENJDK_TARGET_CPU_LEGACY@ export OPENJDK_TARGET_OS="@OPENJDK_TARGET_OS@" export OPENJDK_TARGET_CPU="@OPENJDK_TARGET_CPU@" export OPENJDK_TARGET_CPU_LIBDIR="@OPENJDK_TARGET_CPU_LIBDIR@" +export DEBUG_LEVEL="@DEBUG_LEVEL@" export AWK="@AWK@" export BASH="@BASH@" diff --git a/common/autoconf/configure b/common/autoconf/configure index 6815da9a3b1..547cb33fbc8 100644 --- a/common/autoconf/configure +++ b/common/autoconf/configure @@ -283,7 +283,7 @@ Additional (non-autoconf) OpenJDK Options: EOT - # Print additional help, e.g. a list of toolchains. + # Print additional help, e.g. a list of toolchains and JVM features. # This must be done by the autoconf script. ( CONFIGURE_PRINT_ADDITIONAL_HELP=true . $conf_script_to_run PRINTF=printf ) diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index c7bab7c53a8..7d5056cb47d 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -95,10 +95,8 @@ JDKOPT_SETUP_OPEN_OR_CUSTOM # These are needed to be able to create a configuration name (and thus the output directory) JDKOPT_SETUP_JDK_VARIANT -HOTSPOT_SETUP_JVM_INTERPRETER -HOTSPOT_SETUP_JVM_VARIANTS JDKOPT_SETUP_DEBUG_LEVEL -HOTSPOT_SETUP_DEBUG_LEVEL +HOTSPOT_SETUP_JVM_VARIANTS # With basic setup done, call the custom early hook. CUSTOM_EARLY_HOOK @@ -135,7 +133,6 @@ BASIC_SETUP_DEFAULT_MAKE_TARGET # We need build & target for this. JDKOPT_SETUP_JDK_OPTIONS JDKOPT_SETUP_JLINK_OPTIONS -HOTSPOT_SETUP_HOTSPOT_OPTIONS JDKVER_SETUP_JDK_VERSION_NUMBERS ############################################################################### @@ -207,6 +204,10 @@ FLAGS_SETUP_COMPILER_FLAGS_MISC JDKOPT_SETUP_DEBUG_SYMBOLS JDKOPT_SETUP_CODE_COVERAGE +# Need toolchain to setup dtrace +HOTSPOT_SETUP_DTRACE +HOTSPOT_SETUP_JVM_FEATURES + ############################################################################### # # Check dependencies for external and internal libraries. @@ -225,7 +226,7 @@ LIB_SETUP_LIBRARIES # ############################################################################### -HOTSPOT_SETUP_BUILD_TWEAKS +HOTSPOT_SETUP_LEGACY_BUILD JDKOPT_DETECT_INTREE_EC ############################################################################### @@ -267,6 +268,9 @@ BASIC_TEST_USABILITY_ISSUES # At the end, call the custom hook. (Dummy macro if no custom sources available) CUSTOM_LATE_HOOK +# This needs to be done after CUSTOM_LATE_HOOK since we can setup custom features. +HOTSPOT_VALIDATE_JVM_FEATURES + # We're messing a bit with internal autoconf variables to put the config.status # in the output directory instead of the current directory. CONFIG_STATUS="$CONFIGURESUPPORT_OUTPUTDIR/config.status" diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index b738ef49e22..5e9fc128843 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -61,6 +61,10 @@ AC_DEFUN_ONCE([FLAGS_SETUP_USER_SUPPLIED_FLAGS], AC_SUBST(LEGACY_EXTRA_CXXFLAGS) AC_SUBST(LEGACY_EXTRA_LDFLAGS) + AC_SUBST(EXTRA_CFLAGS) + AC_SUBST(EXTRA_CXXFLAGS) + AC_SUBST(EXTRA_LDFLAGS) + # The global CFLAGS and LDLAGS variables are used by configure tests and # should include the extra parameters CFLAGS="$EXTRA_CFLAGS" @@ -211,8 +215,10 @@ AC_DEFUN_ONCE([FLAGS_SETUP_INIT_FLAGS], # On Windows, we need to set RC flags. if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then RC_FLAGS="-nologo -l0x409" + JVM_RCFLAGS="-nologo" if test "x$DEBUG_LEVEL" = xrelease; then RC_FLAGS="$RC_FLAGS -DNDEBUG" + JVM_RCFLAGS="$JVM_RCFLAGS -DNDEBUG" fi # The version variables used to create RC_FLAGS may be overridden @@ -228,8 +234,19 @@ AC_DEFUN_ONCE([FLAGS_SETUP_INIT_FLAGS], -D\"JDK_COPYRIGHT=Copyright \xA9 $COPYRIGHT_YEAR\" \ -D\"JDK_NAME=\$(PRODUCT_NAME) \$(JDK_RC_PLATFORM_NAME) \$(VERSION_MAJOR)\" \ -D\"JDK_FVER=\$(subst .,\$(COMMA),\$(VERSION_NUMBER_FOUR_POSITIONS))\"" + + JVM_RCFLAGS="$JVM_RCFLAGS \ + -D\"HS_BUILD_ID=\$(VERSION_STRING)\" \ + -D\"HS_COMPANY=\$(COMPANY_NAME)\" \ + -D\"JDK_DOTVER=\$(VERSION_NUMBER_FOUR_POSITIONS)\" \ + -D\"HS_COPYRIGHT=Copyright $COPYRIGHT_YEAR\" \ + -D\"HS_NAME=\$(PRODUCT_NAME) \$(VERSION_SHORT)\" \ + -D\"JDK_VER=\$(subst .,\$(COMMA),\$(VERSION_NUMBER_FOUR_POSITIONS))\" \ + -D\"HS_FNAME=jvm.dll\" \ + -D\"HS_INTERNAL_NAME=jvm\"" fi AC_SUBST(RC_FLAGS) + AC_SUBST(JVM_RCFLAGS) if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then # silence copyright notice and other headers. @@ -237,7 +254,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_INIT_FLAGS], fi ]) -AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], +AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], [ ############################################################################### # @@ -255,6 +272,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], SHARED_LIBRARY_FLAGS ='-undefined dynamic_lookup' else SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG" + JVM_CFLAGS="$JVM_CFLAGS $PICFLAG" fi SET_EXECUTABLE_ORIGIN='-Wl,-rpath,@loader_path/.' SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN" @@ -280,6 +298,10 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN" SET_SHARED_LIBRARY_NAME='-Wl,-install_name,@rpath/[$]1' SET_SHARED_LIBRARY_MAPFILE='-Wl,-exported_symbols_list,[$]1' + + if test "x$STATIC_BUILD" = xfalse; then + JVM_CFLAGS="$JVM_CFLAGS -fPIC" + fi else # Default works for linux, might work on other platforms as well. PICFLAG='-fPIC' @@ -339,11 +361,6 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], AC_SUBST(SET_SHARED_LIBRARY_MAPFILE) AC_SUBST(SHARED_LIBRARY_FLAGS) - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - CFLAGS_JDK="${CFLAGS_JDK} -D__solaris__" - CXXFLAGS_JDK="${CXXFLAGS_JDK} -D__solaris__" - CFLAGS_JDKLIB_EXTRA='-xstrconst' - fi # The (cross) compiler is now configured, we can now test capabilities # of the target platform. ]) @@ -434,6 +451,22 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], AC_SUBST(CFLAGS_DEBUG_SYMBOLS) AC_SUBST(CXXFLAGS_DEBUG_SYMBOLS) + # Debug symbols for JVM_CFLAGS + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -xs" + if test "x$DEBUG_LEVEL" = xslowdebug; then + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -g" + else + # -g0 does not disable inlining, which -g does. + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -g0" + fi + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -Z7 -d2Zi+" + else + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -g" + fi + AC_SUBST(JVM_CFLAGS_SYMBOLS) + # bounds, memory and behavior checking options if test "x$TOOLCHAIN_TYPE" = xgcc; then case $DEBUG_LEVEL in @@ -444,7 +477,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], # no adjustment ;; slowdebug ) - # FIXME: By adding this to C(XX)FLAGS_DEBUG_OPTIONS it + # FIXME: By adding this to C(XX)FLAGS_DEBUG_OPTIONS/JVM_CFLAGS_SYMBOLS it # get's added conditionally on whether we produce debug symbols or not. # This is most likely not really correct. @@ -455,40 +488,59 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], CFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" CXXFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" + if test "x$STACK_PROTECTOR_CFLAG" != x; then + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS $STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" + fi ;; esac fi + if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + if test "x$DEBUG_LEVEL" != xrelease; then + if test "x$OPENJDK_TARGET_CPU" = xx86_64; then + JVM_CFLAGS="$JVM_CFLAGS -homeparams" + fi + fi + fi + # Optimization levels if test "x$TOOLCHAIN_TYPE" = xsolstudio; then CC_HIGHEST="$CC_HIGHEST -fns -fsimple -fsingle -xbuiltin=%all -xdepend -xrestrict -xlibmil" if test "x$OPENJDK_TARGET_CPU_ARCH" = "xx86"; then # FIXME: seems we always set -xregs=no%frameptr; put it elsewhere more global? + C_O_FLAG_HIGHEST_JVM="-xO4" C_O_FLAG_HIGHEST="-xO4 -Wu,-O4~yz $CC_HIGHEST -xalias_level=basic -xregs=no%frameptr" C_O_FLAG_HI="-xO4 -Wu,-O4~yz -xregs=no%frameptr" C_O_FLAG_NORM="-xO2 -Wu,-O2~yz -xregs=no%frameptr" C_O_FLAG_DEBUG="-xregs=no%frameptr" + C_O_FLAG_DEBUG_JVM="" C_O_FLAG_NONE="-xregs=no%frameptr" + CXX_O_FLAG_HIGHEST_JVM="-xO4" CXX_O_FLAG_HIGHEST="-xO4 -Qoption ube -O4~yz $CC_HIGHEST -xregs=no%frameptr" CXX_O_FLAG_HI="-xO4 -Qoption ube -O4~yz -xregs=no%frameptr" CXX_O_FLAG_NORM="-xO2 -Qoption ube -O2~yz -xregs=no%frameptr" CXX_O_FLAG_DEBUG="-xregs=no%frameptr" + CXX_O_FLAG_DEBUG_JVM="" CXX_O_FLAG_NONE="-xregs=no%frameptr" if test "x$OPENJDK_TARGET_CPU_BITS" = "x32"; then C_O_FLAG_HIGHEST="$C_O_FLAG_HIGHEST -xchip=pentium" CXX_O_FLAG_HIGHEST="$CXX_O_FLAG_HIGHEST -xchip=pentium" fi elif test "x$OPENJDK_TARGET_CPU_ARCH" = "xsparc"; then + C_O_FLAG_HIGHEST_JVM="-xO4" C_O_FLAG_HIGHEST="-xO4 -Wc,-Qrm-s -Wc,-Qiselect-T0 $CC_HIGHEST -xalias_level=basic -xprefetch=auto,explicit -xchip=ultra" C_O_FLAG_HI="-xO4 -Wc,-Qrm-s -Wc,-Qiselect-T0" C_O_FLAG_NORM="-xO2 -Wc,-Qrm-s -Wc,-Qiselect-T0" C_O_FLAG_DEBUG="" + C_O_FLAG_DEBUG_JVM="" C_O_FLAG_NONE="" + CXX_O_FLAG_HIGHEST_JVM="-xO4" CXX_O_FLAG_HIGHEST="-xO4 -Qoption cg -Qrm-s -Qoption cg -Qiselect-T0 $CC_HIGHEST -xprefetch=auto,explicit -xchip=ultra" CXX_O_FLAG_HI="-xO4 -Qoption cg -Qrm-s -Qoption cg -Qiselect-T0" CXX_O_FLAG_NORM="-xO2 -Qoption cg -Qrm-s -Qoption cg -Qiselect-T0" CXX_O_FLAG_DEBUG="" + CXX_O_FLAG_DEBUG_JVM="" CXX_O_FLAG_NONE="" fi else @@ -498,48 +550,75 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], if test "x$OPENJDK_TARGET_OS" = xmacosx; then # On MacOSX we optimize for size, something # we should do for all platforms? + C_O_FLAG_HIGHEST_JVM="-Os" C_O_FLAG_HIGHEST="-Os" C_O_FLAG_HI="-Os" C_O_FLAG_NORM="-Os" + C_O_FLAG_SIZE="-Os" else + C_O_FLAG_HIGHEST_JVM="-O3" C_O_FLAG_HIGHEST="-O3" C_O_FLAG_HI="-O3" C_O_FLAG_NORM="-O2" + C_O_FLAG_SIZE="-Os" fi C_O_FLAG_DEBUG="-O0" + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + C_O_FLAG_DEBUG_JVM="" + elif test "x$OPENJDK_TARGET_OS" = xlinux; then + C_O_FLAG_DEBUG_JVM="-O0" + fi C_O_FLAG_NONE="-O0" elif test "x$TOOLCHAIN_TYPE" = xclang; then if test "x$OPENJDK_TARGET_OS" = xmacosx; then # On MacOSX we optimize for size, something # we should do for all platforms? + C_O_FLAG_HIGHEST_JVM="-Os" C_O_FLAG_HIGHEST="-Os" C_O_FLAG_HI="-Os" C_O_FLAG_NORM="-Os" + C_O_FLAG_SIZE="-Os" else + C_O_FLAG_HIGHEST_JVM="-O3" C_O_FLAG_HIGHEST="-O3" C_O_FLAG_HI="-O3" C_O_FLAG_NORM="-O2" + C_O_FLAG_SIZE="-Os" fi C_O_FLAG_DEBUG="-O0" + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + C_O_FLAG_DEBUG_JVM="" + elif test "x$OPENJDK_TARGET_OS" = xlinux; then + C_O_FLAG_DEBUG_JVM="-O0" + fi C_O_FLAG_NONE="-O0" elif test "x$TOOLCHAIN_TYPE" = xxlc; then + C_O_FLAG_HIGHEST_JVM="-O3" C_O_FLAG_HIGHEST="-O3" C_O_FLAG_HI="-O3 -qstrict" C_O_FLAG_NORM="-O2" C_O_FLAG_DEBUG="-qnoopt" + # FIXME: Value below not verified. + C_O_FLAG_DEBUG_JVM="" C_O_FLAG_NONE="-qnoopt" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + C_O_FLAG_HIGHEST_JVM="-O2 -Oy-" C_O_FLAG_HIGHEST="-O2" C_O_FLAG_HI="-O1" C_O_FLAG_NORM="-O1" C_O_FLAG_DEBUG="-Od" + C_O_FLAG_DEBUG_JVM="" C_O_FLAG_NONE="-Od" + C_O_FLAG_SIZE="-Os" fi + CXX_O_FLAG_HIGHEST_JVM="$C_O_FLAG_HIGHEST_JVM" CXX_O_FLAG_HIGHEST="$C_O_FLAG_HIGHEST" CXX_O_FLAG_HI="$C_O_FLAG_HI" CXX_O_FLAG_NORM="$C_O_FLAG_NORM" CXX_O_FLAG_DEBUG="$C_O_FLAG_DEBUG" + CXX_O_FLAG_DEBUG_JVM="$C_O_FLAG_DEBUG_JVM" CXX_O_FLAG_NONE="$C_O_FLAG_NONE" + CXX_O_FLAG_SIZE="$C_O_FLAG_SIZE" fi # Adjust optimization flags according to debug level. @@ -554,260 +633,43 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], ;; slowdebug ) # Disable optimization + C_O_FLAG_HIGHEST_JVM="$C_O_FLAG_DEBUG_JVM" C_O_FLAG_HIGHEST="$C_O_FLAG_DEBUG" C_O_FLAG_HI="$C_O_FLAG_DEBUG" C_O_FLAG_NORM="$C_O_FLAG_DEBUG" + C_O_FLAG_SIZE="$C_O_FLAG_DEBUG" + CXX_O_FLAG_HIGHEST_JVM="$CXX_O_FLAG_DEBUG_JVM" CXX_O_FLAG_HIGHEST="$CXX_O_FLAG_DEBUG" CXX_O_FLAG_HI="$CXX_O_FLAG_DEBUG" CXX_O_FLAG_NORM="$CXX_O_FLAG_DEBUG" + CXX_O_FLAG_SIZE="$CXX_O_FLAG_DEBUG" ;; esac + AC_SUBST(C_O_FLAG_HIGHEST_JVM) AC_SUBST(C_O_FLAG_HIGHEST) AC_SUBST(C_O_FLAG_HI) AC_SUBST(C_O_FLAG_NORM) AC_SUBST(C_O_FLAG_DEBUG) AC_SUBST(C_O_FLAG_NONE) + AC_SUBST(C_O_FLAG_SIZE) + AC_SUBST(CXX_O_FLAG_HIGHEST_JVM) AC_SUBST(CXX_O_FLAG_HIGHEST) AC_SUBST(CXX_O_FLAG_HI) AC_SUBST(CXX_O_FLAG_NORM) AC_SUBST(CXX_O_FLAG_DEBUG) AC_SUBST(CXX_O_FLAG_NONE) + AC_SUBST(CXX_O_FLAG_SIZE) ]) -AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], + +AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], [ - # Special extras... - if test "x$TOOLCHAIN_TYPE" = xsolstudio; then - if test "x$OPENJDK_TARGET_CPU_ARCH" = "xsparc"; then - CFLAGS_JDKLIB_EXTRA="${CFLAGS_JDKLIB_EXTRA} -xregs=no%appl" - CXXFLAGS_JDKLIB_EXTRA="${CXXFLAGS_JDKLIB_EXTRA} -xregs=no%appl" - fi - CFLAGS_JDKLIB_EXTRA="${CFLAGS_JDKLIB_EXTRA} -errtags=yes -errfmt" - CXXFLAGS_JDKLIB_EXTRA="${CXXFLAGS_JDKLIB_EXTRA} -errtags=yes -errfmt" - elif test "x$TOOLCHAIN_TYPE" = xxlc; then - CFLAGS_JDK="${CFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" - CXXFLAGS_JDK="${CXXFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" - elif test "x$TOOLCHAIN_TYPE" = xgcc; then - CXXSTD_CXXFLAG="-std=gnu++98" - FLAGS_CXX_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$CXXSTD_CXXFLAG -Werror], - IF_FALSE: [CXXSTD_CXXFLAG=""]) - CXXFLAGS_JDK="${CXXFLAGS_JDK} ${CXXSTD_CXXFLAG}" - AC_SUBST([CXXSTD_CXXFLAG]) - fi - CFLAGS_JDK="${CFLAGS_JDK} $EXTRA_CFLAGS" - CXXFLAGS_JDK="${CXXFLAGS_JDK} $EXTRA_CXXFLAGS" - LDFLAGS_JDK="${LDFLAGS_JDK} $EXTRA_LDFLAGS" - - ############################################################################### - # - # Now setup the CFLAGS and LDFLAGS for the JDK build. - # Later we will also have CFLAGS and LDFLAGS for the hotspot subrepo build. - # - - # Setup compiler/platform specific flags into - # CFLAGS_JDK - C Compiler flags - # CXXFLAGS_JDK - C++ Compiler flags - # COMMON_CCXXFLAGS_JDK - common to C and C++ - if test "x$TOOLCHAIN_TYPE" = xgcc; then - if test "x$OPENJDK_TARGET_CPU" = xx86; then - # Force compatibility with i586 on 32 bit intel platforms. - COMMON_CCXXFLAGS="${COMMON_CCXXFLAGS} -march=i586" - fi - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ - -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" - case $OPENJDK_TARGET_CPU_ARCH in - arm ) - # on arm we don't prevent gcc to omit frame pointer but do prevent strict aliasing - CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing" - ;; - ppc ) - # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing - CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing" - ;; - * ) - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer" - CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing" - ;; - esac - TOOLCHAIN_CHECK_COMPILER_VERSION(VERSION: 6, IF_AT_LEAST: FLAGS_SETUP_GCC6_COMPILER_FLAGS) - elif test "x$TOOLCHAIN_TYPE" = xclang; then - if test "x$OPENJDK_TARGET_OS" = xlinux; then - if test "x$OPENJDK_TARGET_CPU" = xx86; then - # Force compatibility with i586 on 32 bit intel platforms. - COMMON_CCXXFLAGS="${COMMON_CCXXFLAGS} -march=i586" - fi - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ - -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" - case $OPENJDK_TARGET_CPU_ARCH in - ppc ) - # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing - CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing" - ;; - * ) - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer" - CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing" - ;; - esac - fi - elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -DTRACING -DMACRO_MEMSYS_OPS -DBREAKPTS" - if test "x$OPENJDK_TARGET_CPU_ARCH" = xx86; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DcpuIntel -Di586 -D$OPENJDK_TARGET_CPU_LEGACY_LIB" - fi - - CFLAGS_JDK="$CFLAGS_JDK -xc99=%none -xCC -errshort=tags -Xa -v -mt -W0,-noglobal" - CXXFLAGS_JDK="$CXXFLAGS_JDK -errtags=yes +w -mt -features=no%except -DCC_NOEX -norunpath -xnolib" - elif test "x$TOOLCHAIN_TYPE" = xxlc; then - CFLAGS_JDK="$CFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" - CXXFLAGS_JDK="$CXXFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" - elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK \ - -MD -Zc:wchar_t- -W3 -wd4800 \ - -DWIN32_LEAN_AND_MEAN \ - -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE \ - -D_WINSOCK_DEPRECATED_NO_WARNINGS \ - -DWIN32 -DIAL" - if test "x$OPENJDK_TARGET_CPU" = xx86_64; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_AMD64_ -Damd64" - else - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_X86_ -Dx86" - fi - # If building with Visual Studio 2010, we can still use _STATIC_CPPLIB to - # avoid bundling msvcpNNN.dll. Doesn't work with newer versions of visual - # studio. - if test "x$TOOLCHAIN_VERSION" = "x2010"; then - STATIC_CPPLIB_FLAGS="-D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB" - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK $STATIC_CPPLIB_FLAGS" - fi - fi - - ############################################################################### - - # Adjust flags according to debug level. - case $DEBUG_LEVEL in - fastdebug | slowdebug ) - CFLAGS_JDK="$CFLAGS_JDK $CFLAGS_DEBUG_SYMBOLS $CFLAGS_DEBUG_OPTIONS" - CXXFLAGS_JDK="$CXXFLAGS_JDK $CXXFLAGS_DEBUG_SYMBOLS $CXXFLAGS_DEBUG_OPTIONS" - JAVAC_FLAGS="$JAVAC_FLAGS -g" - ;; - release ) - ;; - * ) - AC_MSG_ERROR([Unrecognized \$DEBUG_LEVEL: $DEBUG_LEVEL]) - ;; - esac - - # Set some common defines. These works for all compilers, but assume - # -D is universally accepted. - - # Setup endianness - if test "x$OPENJDK_TARGET_CPU_ENDIAN" = xlittle; then - # The macro _LITTLE_ENDIAN needs to be defined the same to avoid the - # Sun C compiler warning message: warning: macro redefined: _LITTLE_ENDIAN - # (The Solaris X86 system defines this in file /usr/include/sys/isa_defs.h). - # Note: -Dmacro is the same as #define macro 1 - # -Dmacro= is the same as #define macro - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_LITTLE_ENDIAN=" - else - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_LITTLE_ENDIAN" - fi - else - # Same goes for _BIG_ENDIAN. Do we really need to set *ENDIAN on Solaris if they - # are defined in the system? - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_BIG_ENDIAN=" - else - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_BIG_ENDIAN" - fi - fi - - # Setup target OS define. Use OS target name but in upper case. - OPENJDK_TARGET_OS_UPPERCASE=`$ECHO $OPENJDK_TARGET_OS | $TR 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D$OPENJDK_TARGET_OS_UPPERCASE" - - # Setup target CPU - OPENJDK_TARGET_CCXXFLAGS_JDK="$OPENJDK_TARGET_CCXXFLAGS_JDK \ - $ADD_LP64 \ - -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY" - OPENJDK_BUILD_CCXXFLAGS_JDK="$OPENJDK_BUILD_CCXXFLAGS_JDK \ - $OPENJDK_BUILD_ADD_LP64 \ - -DARCH='\"$OPENJDK_BUILD_CPU_LEGACY\"' -D$OPENJDK_BUILD_CPU_LEGACY" - - # Setup debug/release defines - if test "x$DEBUG_LEVEL" = xrelease; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DNDEBUG" - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DTRIMMED" - fi - else - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DDEBUG" - fi - - # Set some additional per-OS defines. - if test "x$OPENJDK_TARGET_OS" = xmacosx; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" - elif test "x$OPENJDK_TARGET_OS" = xbsd; then - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE" - fi - - # Additional macosx handling - if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Setting these parameters makes it an error to link to macosx APIs that are - # newer than the given OS version and makes the linked binaries compatible - # even if built on a newer version of the OS. - # The expected format is X.Y.Z - MACOSX_VERSION_MIN=10.7.0 - AC_SUBST(MACOSX_VERSION_MIN) - - # The macro takes the version with no dots, ex: 1070 - # Let the flags variables get resolved in make for easier override on make - # command line. - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DMAC_OS_X_VERSION_MAX_ALLOWED=\$(subst .,,\$(MACOSX_VERSION_MIN)) -mmacosx-version-min=\$(MACOSX_VERSION_MIN)" - LDFLAGS_JDK="$LDFLAGS_JDK -mmacosx-version-min=\$(MACOSX_VERSION_MIN)" - fi - - # Setup some hard coded includes - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK \ - -I${JDK_TOPDIR}/src/java.base/share/native/include \ - -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS/native/include \ - -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/include \ - -I${JDK_TOPDIR}/src/java.base/share/native/libjava \ - -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/libjava" - - # The shared libraries are compiled using the picflag. - CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ - $CFLAGS_JDK $EXTRA_CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" - CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ - $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" - - # Executable flags - CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ - $CFLAGS_JDK $EXTRA_CFLAGS_JDK" - CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ - $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK" - - # The corresponding flags for building for the build platform. This is still an - # approximation, we only need something that runs on this machine when cross - # compiling the product. - OPENJDK_BUILD_CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \ - $PICFLAG $CFLAGS_JDKLIB_EXTRA" - OPENJDK_BUILD_CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \ - $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" - OPENJDK_BUILD_CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK" - OPENJDK_BUILD_CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK" - - AC_SUBST(CFLAGS_JDKLIB) - AC_SUBST(CFLAGS_JDKEXE) - AC_SUBST(CXXFLAGS_JDKLIB) - AC_SUBST(CXXFLAGS_JDKEXE) - AC_SUBST(OPENJDK_BUILD_CFLAGS_JDKLIB) - AC_SUBST(OPENJDK_BUILD_CFLAGS_JDKEXE) - AC_SUBST(OPENJDK_BUILD_CXXFLAGS_JDKLIB) - AC_SUBST(OPENJDK_BUILD_CXXFLAGS_JDKEXE) + FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER([TARGET]) + FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER([BUILD], [OPENJDK_BUILD_]) + # Tests are only ever compiled for TARGET # Flags for compiling test libraries CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" CXXFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" @@ -821,52 +683,425 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], AC_SUBST(CXXFLAGS_TESTLIB) AC_SUBST(CXXFLAGS_TESTEXE) + LDFLAGS_TESTLIB="$LDFLAGS_JDKLIB" + LDFLAGS_TESTEXE="$LDFLAGS_JDKEXE" + + AC_SUBST(LDFLAGS_TESTLIB) + AC_SUBST(LDFLAGS_TESTEXE) + +]) + +################################################################################ +# $1 - Either BUILD or TARGET to pick the correct OS/CPU variables to check +# conditionals against. +# $2 - Optional prefix for each variable defined. +AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], +[ + # Special extras... + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + if test "x$OPENJDK_$1_CPU_ARCH" = "xsparc"; then + $2CFLAGS_JDKLIB_EXTRA="${$2CFLAGS_JDKLIB_EXTRA} -xregs=no%appl" + $2CXXFLAGS_JDKLIB_EXTRA="${$2CXXFLAGS_JDKLIB_EXTRA} -xregs=no%appl" + fi + $2CFLAGS_JDKLIB_EXTRA="${$2CFLAGS_JDKLIB_EXTRA} -errtags=yes -errfmt" + $2CXXFLAGS_JDKLIB_EXTRA="${$2CXXFLAGS_JDKLIB_EXTRA} -errtags=yes -errfmt" + elif test "x$TOOLCHAIN_TYPE" = xxlc; then + $2CFLAGS_JDK="${$2CFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + $2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + elif test "x$TOOLCHAIN_TYPE" = xgcc; then + $2CXXSTD_CXXFLAG="-std=gnu++98" + FLAGS_CXX_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [[$]$2CXXSTD_CXXFLAG -Werror], + IF_FALSE: [$2CXXSTD_CXXFLAG=""]) + $2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} ${$2CXXSTD_CXXFLAG}" + AC_SUBST([$2CXXSTD_CXXFLAG]) + fi + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + $2CFLAGS_JDK="${$2CFLAGS_JDK} -D__solaris__" + $2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} -D__solaris__" + $2CFLAGS_JDKLIB_EXTRA='-xstrconst' + CFLAGS_JDK="${CFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + CXXFLAGS_JDK="${CXXFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + fi + + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + $2CFLAGS_JDK="${$2CFLAGS_JDK} -D__solaris__" + $2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} -D__solaris__" + $2CFLAGS_JDKLIB_EXTRA='-xstrconst' + fi + + $2CFLAGS_JDK="${$2CFLAGS_JDK} ${$2EXTRA_CFLAGS}" + $2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} ${$2EXTRA_CXXFLAGS}" + $2LDFLAGS_JDK="${$2LDFLAGS_JDK} ${$2EXTRA_LDFLAGS}" + + ############################################################################### + # + # Now setup the CFLAGS and LDFLAGS for the JDK build. + # Later we will also have CFLAGS and LDFLAGS for the hotspot subrepo build. + # + + # Setup compiler/platform specific flags into + # $2CFLAGS_JDK - C Compiler flags + # $2CXXFLAGS_JDK - C++ Compiler flags + # $2COMMON_CCXXFLAGS_JDK - common to C and C++ + if test "x$TOOLCHAIN_TYPE" = xgcc; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_GNU_SOURCE" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_REENTRANT" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -fcheck-new" + if test "x$OPENJDK_$1_CPU" = xx86; then + # Force compatibility with i586 on 32 bit intel platforms. + $2COMMON_CCXXFLAGS="${$2COMMON_CCXXFLAGS} -march=i586" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -march=i586" + fi + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS [$]$2COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ + -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" + case $OPENJDK_$1_CPU_ARCH in + arm ) + # on arm we don't prevent gcc to omit frame pointer but do prevent strict aliasing + $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" + ;; + ppc ) + # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing + $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" + ;; + * ) + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer" + $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" + ;; + esac + TOOLCHAIN_CHECK_COMPILER_VERSION(VERSION: 6, IF_AT_LEAST: FLAGS_SETUP_GCC6_COMPILER_FLAGS) + elif test "x$TOOLCHAIN_TYPE" = xclang; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_GNU_SOURCE" + + # Restrict the debug information created by Clang to avoid + # too big object files and speed the build up a little bit + # (see http://llvm.org/bugs/show_bug.cgi?id=7554) + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -flimit-debug-info" + if test "x$OPENJDK_$1_OS" = xlinux; then + if test "x$OPENJDK_$1_CPU" = xx86; then + # Force compatibility with i586 on 32 bit intel platforms. + $2COMMON_CCXXFLAGS="${$2COMMON_CCXXFLAGS} -march=i586" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -march=i586" + fi + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -Wno-sometimes-uninitialized" + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS [$]$2COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ + -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" + case $OPENJDK_$1_CPU_ARCH in + ppc ) + # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing + $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" + ;; + * ) + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer" + $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" + ;; + esac + fi + elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -DSPARC_WORKS" + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS [$]$2COMMON_CCXXFLAGS_JDK -DTRACING -DMACRO_MEMSYS_OPS -DBREAKPTS" + if test "x$OPENJDK_$1_CPU_ARCH" = xx86; then + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -DcpuIntel -Di586 -D$OPENJDK_$1_CPU_LEGACY_LIB" + fi + + $2CFLAGS_JDK="[$]$2CFLAGS_JDK -xc99=%none -xCC -errshort=tags -Xa -v -mt -W0,-noglobal" + $2CXXFLAGS_JDK="[$]$2CXXFLAGS_JDK -errtags=yes +w -mt -features=no%except -DCC_NOEX -norunpath -xnolib" + elif test "x$TOOLCHAIN_TYPE" = xxlc; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_REENTRANT -D__STDC_FORMAT_MACROS" + $2CFLAGS_JDK="[$]$2CFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" + $2CXXFLAGS_JDK="[$]$2CXXFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS [$]$2COMMON_CCXXFLAGS_JDK \ + -MD -Zc:wchar_t- -W3 -wd4800 \ + -DWIN32_LEAN_AND_MEAN \ + -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE \ + -D_WINSOCK_DEPRECATED_NO_WARNINGS \ + -DWIN32 -DIAL" + if test "x$OPENJDK_$1_CPU" = xx86_64; then + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D_AMD64_ -Damd64" + else + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D_X86_ -Dx86" + fi + # If building with Visual Studio 2010, we can still use _STATIC_CPPLIB to + # avoid bundling msvcpNNN.dll. Doesn't work with newer versions of visual + # studio. + if test "x$TOOLCHAIN_VERSION" = "x2010"; then + STATIC_CPPLIB_FLAGS="-D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB" + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK $STATIC_CPPLIB_FLAGS" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS $STATIC_CPPLIB_FLAGS" + fi + fi + + ############################################################################### + + # Adjust flags according to debug level. + case $DEBUG_LEVEL in + fastdebug | slowdebug ) + $2CFLAGS_JDK="[$]$2CFLAGS_JDK $CFLAGS_DEBUG_SYMBOLS $CFLAGS_DEBUG_OPTIONS" + $2CXXFLAGS_JDK="[$]$2CXXFLAGS_JDK $CXXFLAGS_DEBUG_SYMBOLS $CXXFLAGS_DEBUG_OPTIONS" + JAVAC_FLAGS="$JAVAC_FLAGS -g" + ;; + release ) + ;; + * ) + AC_MSG_ERROR([Unrecognized \$DEBUG_LEVEL: $DEBUG_LEVEL]) + ;; + esac + + # Set some common defines. These works for all compilers, but assume + # -D is universally accepted. + + # Setup endianness + if test "x$OPENJDK_$1_CPU_ENDIAN" = xlittle; then + # The macro _LITTLE_ENDIAN needs to be defined the same to avoid the + # Sun C compiler warning message: warning: macro redefined: _LITTLE_ENDIAN + # (The Solaris X86 system defines this in file /usr/include/sys/isa_defs.h). + # Note: -Dmacro is the same as #define macro 1 + # -Dmacro= is the same as #define macro + if test "x$OPENJDK_$1_OS" = xsolaris; then + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D_LITTLE_ENDIAN=" + else + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D_LITTLE_ENDIAN" + fi + else + # Same goes for _BIG_ENDIAN. Do we really need to set *ENDIAN on Solaris if they + # are defined in the system? + if test "x$OPENJDK_$1_OS" = xsolaris; then + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D_BIG_ENDIAN=" + else + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D_BIG_ENDIAN" + fi + fi + + # Setup target OS define. Use OS target name but in upper case. + OPENJDK_$1_OS_UPPERCASE=`$ECHO $OPENJDK_$1_OS | $TR 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D$OPENJDK_$1_OS_UPPERCASE" + + # Setup target CPU + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK \ + $OPENJDK_$1_ADD_LP64 \ + -DARCH='\"$OPENJDK_$1_CPU_LEGACY\"' -D$OPENJDK_$1_CPU_LEGACY" + + # Setup debug/release defines + if test "x$DEBUG_LEVEL" = xrelease; then + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -DNDEBUG" + if test "x$OPENJDK_$1_OS" = xsolaris; then + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -DTRIMMED" + fi + else + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -DDEBUG" + fi + + # Set some additional per-OS defines. + if test "x$OPENJDK_$1_OS" = xlinux; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -DLINUX" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -pipe -fPIC -fno-rtti -fno-exceptions \ + -fvisibility=hidden -fno-strict-aliasing -fno-omit-frame-pointer" + elif test "x$OPENJDK_$1_OS" = xsolaris; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -DSOLARIS" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -template=no%extdef -features=no%split_init \ + -D_Crun_inline_placement -library=%none -KPIC -mt -xwe -features=no%except" + elif test "x$OPENJDK_$1_OS" = xmacosx; then + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_ALLBSD_SOURCE" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -fno-rtti -fno-exceptions -fvisibility=hidden \ + -mno-omit-leaf-frame-pointer -mstack-alignment=16 -pipe -fno-strict-aliasing \ + -DMAC_OS_X_VERSION_MAX_ALLOWED=1070 -mmacosx-version-min=10.7.0 \ + -fno-omit-frame-pointer" + elif test "x$OPENJDK_$1_OS" = xaix; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -DAIX" + # We may need '-qminimaltoc' or '-qpic=large -bbigtoc' if the TOC overflows. + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -qtune=balanced -qhot=level=1 -qinline \ + -qinlglue -qalias=noansi -qstrict -qtls=default -qlanglvl=c99vla \ + -qlanglvl=noredefmac -qnortti -qnoeh -qignerrno" + elif test "x$OPENJDK_$1_OS" = xbsd; then + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE" + elif test "x$OPENJDK_$1_OS" = xwindows; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_WINDOWS -DWIN32 -D_JNI_IMPLEMENTATION_" + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -nologo -W3 -MD -MP" + fi + + # Set some additional per-CPU defines. + if test "x$OPENJDK_$1_OS-$OPENJDK_$1_CPU" = xwindows-x86; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -arch:IA32" + elif test "x$OPENJDK_$1_CPU" = xsparcv9; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -xarch=sparc" + elif test "x$OPENJDK_$1_CPU" = xppc64; then + if test "x$OPENJDK_$1_OS" = xlinux; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -minsert-sched-nops=regroup_exact -mno-multiple -mno-string" + if test "x$OPENJDK_$1_CPU_ENDIAN" = xbig; then + # fixes `relocation truncated to fit' error for gcc 4.1. + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mminimal-toc" + # Use ppc64 instructions, but schedule for power5 + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mcpu=powerpc64 -mtune=power5" + else + # Little endian machine uses ELFv2 ABI. + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -DABI_ELFv2" + # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mcpu=power7 -mtune=power8" + fi + elif test "x$OPENJDK_$1_OS" = xaix; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -qarch=ppc64" + fi + fi + + if test "x$OPENJDK_$1_CPU_ENDIAN" = xlittle; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -DVM_LITTLE_ENDIAN" + fi + + if test "x$OPENJDK_$1_CPU_BITS" = x64; then + if test "x$OPENJDK_$1_OS" != xsolaris && test "x$OPENJDK_$1_OS" != xaix; then + # Solaris does not have _LP64=1 in the old build. + # xlc on AIX defines _LP64=1 by default and issues a warning if we redefine it. + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_LP64=1" + fi + fi + + # Set $2JVM_CFLAGS warning handling + if test "x$OPENJDK_$1_OS" = xlinux; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -Wpointer-arith -Wsign-compare -Wunused-function \ + -Wunused-value -Woverloaded-virtual" + + if test "x$TOOLCHAIN_TYPE" = xgcc; then + TOOLCHAIN_CHECK_COMPILER_VERSION(VERSION: [4.8], + IF_AT_LEAST: [ + # These flags either do not work or give spurious warnings prior to gcc 4.8. + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -Wno-format-zero-length -Wtype-limits -Wuninitialized" + ] + ) + fi + if ! HOTSPOT_CHECK_JVM_VARIANT(zero) && ! HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + # Non-zero builds have stricter warnings + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -Wreturn-type -Wundef -Wformat=2" + else + if test "x$TOOLCHAIN_TYPE" = xclang; then + # Some versions of llvm do not like -Wundef + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -Wno-undef" + fi + fi + elif test "x$OPENJDK_$1_OS" = xmacosx; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -Wno-deprecated -Wpointer-arith \ + -Wsign-compare -Wundef -Wunused-function -Wformat=2" + fi + + # Additional macosx handling + if test "x$OPENJDK_$1_OS" = xmacosx; then + # Setting these parameters makes it an error to link to macosx APIs that are + # newer than the given OS version and makes the linked binaries compatible + # even if built on a newer version of the OS. + # The expected format is X.Y.Z + MACOSX_VERSION_MIN=10.7.0 + AC_SUBST(MACOSX_VERSION_MIN) + + # The macro takes the version with no dots, ex: 1070 + # Let the flags variables get resolved in make for easier override on make + # command line. + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -DMAC_OS_X_VERSION_MAX_ALLOWED=\$(subst .,,\$(MACOSX_VERSION_MIN)) -mmacosx-version-min=\$(MACOSX_VERSION_MIN)" + $2LDFLAGS_JDK="[$]$2LDFLAGS_JDK -mmacosx-version-min=\$(MACOSX_VERSION_MIN)" + fi + + # Setup some hard coded includes + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK \ + -I${JDK_TOPDIR}/src/java.base/share/native/include \ + -I${JDK_TOPDIR}/src/java.base/$OPENJDK_$1_OS/native/include \ + -I${JDK_TOPDIR}/src/java.base/$OPENJDK_$1_OS_TYPE/native/include \ + -I${JDK_TOPDIR}/src/java.base/share/native/libjava \ + -I${JDK_TOPDIR}/src/java.base/$OPENJDK_$1_OS_TYPE/native/libjava" + + # The shared libraries are compiled using the picflag. + $2CFLAGS_JDKLIB="[$]$2COMMON_CCXXFLAGS_JDK \ + [$]$2CFLAGS_JDK [$]$2EXTRA_CFLAGS_JDK $PICFLAG [$]$2CFLAGS_JDKLIB_EXTRA" + $2CXXFLAGS_JDKLIB="[$]$2COMMON_CCXXFLAGS_JDK \ + [$]$2CXXFLAGS_JDK [$]$2EXTRA_CXXFLAGS_JDK $PICFLAG [$]$2CXXFLAGS_JDKLIB_EXTRA" + + # Executable flags + $2CFLAGS_JDKEXE="[$]$2COMMON_CCXXFLAGS_JDK [$]$2CFLAGS_JDK [$]$2EXTRA_CFLAGS_JDK" + $2CXXFLAGS_JDKEXE="[$]$2COMMON_CCXXFLAGS_JDK [$]$2CXXFLAGS_JDK [$]$2EXTRA_CXXFLAGS_JDK" + + AC_SUBST($2CFLAGS_JDKLIB) + AC_SUBST($2CFLAGS_JDKEXE) + AC_SUBST($2CXXFLAGS_JDKLIB) + AC_SUBST($2CXXFLAGS_JDKEXE) + # Setup LDFLAGS et al. # if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then LDFLAGS_MICROSOFT="-nologo -opt:ref" - LDFLAGS_JDK="$LDFLAGS_JDK $LDFLAGS_MICROSOFT -incremental:no" - if test "x$OPENJDK_TARGET_CPU_BITS" = "x32"; then + $2LDFLAGS_JDK="[$]$2LDFLAGS_JDK $LDFLAGS_MICROSOFT -incremental:no" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LDFLAGS_MICROSOFT -opt:icf,8 -subsystem:windows -base:0x8000000" + if test "x$OPENJDK_$1_CPU_BITS" = "x32"; then LDFLAGS_SAFESH="-safeseh" - LDFLAGS_JDK="$LDFLAGS_JDK $LDFLAGS_SAFESH" + $2LDFLAGS_JDK="[$]$2LDFLAGS_JDK $LDFLAGS_SAFESH" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LDFLAGS_SAFESH" + # NOTE: Old build added -machine. Probably not needed. + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -machine:I386" + else + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -machine:AMD64" + fi + elif test "x$TOOLCHAIN_TYPE" = xclang; then + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -mno-omit-leaf-frame-pointer -mstack-alignment=16 -stdlib=libstdc++ -fPIC" + if test "x$OPENJDK_$1_OS" = xmacosx; then + # FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead. + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." fi elif test "x$TOOLCHAIN_TYPE" = xgcc; then # If this is a --hash-style=gnu system, use --hash-style=both, why? # We have previously set HAS_GNU_HASH if this is the case if test -n "$HAS_GNU_HASH"; then - LDFLAGS_HASH_STYLE="-Wl,--hash-style=both" - LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_HASH_STYLE" + $2LDFLAGS_HASH_STYLE="-Wl,--hash-style=both" + $2LDFLAGS_JDK="${$2LDFLAGS_JDK} [$]$2LDFLAGS_HASH_STYLE" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS [$]$2LDFLAGS_HASH_STYLE" fi - if test "x$OPENJDK_TARGET_OS" = xlinux; then + if test "x$OPENJDK_$1_OS" = xmacosx; then + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." + fi + if test "x$OPENJDK_$1_OS" = xlinux; then # And since we now know that the linker is gnu, then add -z defs, to forbid # undefined symbols in object files. LDFLAGS_NO_UNDEF_SYM="-Wl,-z,defs" - LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_NO_UNDEF_SYM" + $2LDFLAGS_JDK="${$2LDFLAGS_JDK} $LDFLAGS_NO_UNDEF_SYM" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LDFLAGS_NO_UNDEF_SYM" + LDFLAGS_NO_EXEC_STACK="-Wl,-z,noexecstack" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LDFLAGS_NO_EXEC_STACK" + if test "x$OPENJDK_$1_CPU" = xx86; then + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -march=i586" + fi case $DEBUG_LEVEL in release ) # tell linker to optimize libraries. # Should this be supplied to the OSS linker as well? LDFLAGS_DEBUGLEVEL_release="-Wl,-O1" - LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_DEBUGLEVEL_release" + $2LDFLAGS_JDK="${$2LDFLAGS_JDK} $LDFLAGS_DEBUGLEVEL_release" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LDFLAGS_DEBUGLEVEL_release" + if test "x$HAS_LINKER_RELRO" = "xtrue"; then + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LINKER_RELRO_FLAG" + fi ;; slowdebug ) + # Hotspot always let the linker optimize + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -Wl,-O1" if test "x$HAS_LINKER_NOW" = "xtrue"; then # do relocations at load - LDFLAGS_JDK="$LDFLAGS_JDK $LINKER_NOW_FLAG" - LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LINKER_NOW_FLAG" + $2LDFLAGS_JDK="[$]$2LDFLAGS_JDK $LINKER_NOW_FLAG" + $2LDFLAGS_CXX_JDK="[$]$2LDFLAGS_CXX_JDK $LINKER_NOW_FLAG" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LINKER_NOW_FLAG" fi if test "x$HAS_LINKER_RELRO" = "xtrue"; then # mark relocations read only - LDFLAGS_JDK="$LDFLAGS_JDK $LINKER_RELRO_FLAG" - LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LINKER_RELRO_FLAG" + $2LDFLAGS_JDK="[$]$2LDFLAGS_JDK $LINKER_RELRO_FLAG" + $2LDFLAGS_CXX_JDK="[$]$2LDFLAGS_CXX_JDK $LINKER_RELRO_FLAG" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LINKER_RELRO_FLAG" fi ;; fastdebug ) + # Hotspot always let the linker optimize + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -Wl,-O1" if test "x$HAS_LINKER_RELRO" = "xtrue"; then # mark relocations read only - LDFLAGS_JDK="$LDFLAGS_JDK $LINKER_RELRO_FLAG" - LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LINKER_RELRO_FLAG" + $2LDFLAGS_JDK="[$]$2LDFLAGS_JDK $LINKER_RELRO_FLAG" + $2LDFLAGS_CXX_JDK="[$]$2LDFLAGS_CXX_JDK $LINKER_RELRO_FLAG" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LINKER_RELRO_FLAG" fi ;; * ) @@ -876,85 +1111,122 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], fi elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then LDFLAGS_SOLSTUDIO="-Wl,-z,defs" - LDFLAGS_JDK="$LDFLAGS_JDK $LDFLAGS_SOLSTUDIO -xildoff -ztext" + $2LDFLAGS_JDK="[$]$2LDFLAGS_JDK $LDFLAGS_SOLSTUDIO -xildoff -ztext" LDFLAGS_CXX_SOLSTUDIO="-norunpath" - LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LDFLAGS_CXX_SOLSTUDIO -xnolib" + $2LDFLAGS_CXX_JDK="[$]$2LDFLAGS_CXX_JDK $LDFLAGS_CXX_SOLSTUDIO -xnolib" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LDFLAGS_SOLSTUDIO -library=%none -mt $LDFLAGS_CXX_SOLSTUDIO -z noversion" + if test "x$OPENJDK_$1_CPU_ARCH" = "xsparc"; then + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -xarch=sparc" + fi elif test "x$TOOLCHAIN_TYPE" = xxlc; then LDFLAGS_XLC="-b64 -brtl -bnolibpath -bexpall -bernotok" - LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_XLC" + $2LDFLAGS_JDK="${$2LDFLAGS_JDK} $LDFLAGS_XLC" + $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LDFLAGS_XLC" fi # Customize LDFLAGS for executables - LDFLAGS_JDKEXE="${LDFLAGS_JDK}" + $2LDFLAGS_JDKEXE="${$2LDFLAGS_JDK}" if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then - if test "x$OPENJDK_TARGET_CPU_BITS" = "x64"; then + if test "x$OPENJDK_$1_CPU_BITS" = "x64"; then LDFLAGS_STACK_SIZE=1048576 else LDFLAGS_STACK_SIZE=327680 fi - LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE} /STACK:$LDFLAGS_STACK_SIZE" - elif test "x$OPENJDK_TARGET_OS" = xlinux; then - LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined" + $2LDFLAGS_JDKEXE="${$2LDFLAGS_JDKEXE} /STACK:$LDFLAGS_STACK_SIZE" + elif test "x$OPENJDK_$1_OS" = xlinux; then + $2LDFLAGS_JDKEXE="[$]$2LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined" fi - OPENJDK_BUILD_LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE}" - LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE} ${EXTRA_LDFLAGS_JDK}" + $2LDFLAGS_JDKEXE="${$2LDFLAGS_JDKEXE} ${$2EXTRA_LDFLAGS_JDK}" # Customize LDFLAGS for libs - LDFLAGS_JDKLIB="${LDFLAGS_JDK}" + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDK}" - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}" + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}" if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \ + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} \ -libpath:${OUTPUT_ROOT}/support/modules_libs/java.base" - JDKLIB_LIBS="" + $2JDKLIB_LIBS="" else - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \ - -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)" + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} \ + -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)" + if test "x$1" = "xTARGET"; then # On some platforms (mac) the linker warns about non existing -L dirs. # Add server first if available. Linking aginst client does not always produce the same results. - # Only add client dir if client is being built. Add minimal (note not minimal1) if only building minimal1. + # Only add client/minimal dir if client/minimal is being built. # Default to server for other variants. - if test "x$JVM_VARIANT_SERVER" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" - elif test "x$JVM_VARIANT_CLIENT" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/client" - elif test "x$JVM_VARIANT_MINIMAL1" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/minimal" + if HOTSPOT_CHECK_JVM_VARIANT(server); then + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/server" + elif HOTSPOT_CHECK_JVM_VARIANT(client); then + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/client" + elif HOTSPOT_CHECK_JVM_VARIANT(minimal); then + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/minimal" else - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/server" + fi + elif test "x$1" = "xBUILD"; then + # When building a buildjdk, it's always only the server variant + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} \ + -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/server" fi - JDKLIB_LIBS="-ljava -ljvm" + $2JDKLIB_LIBS="-ljava -ljvm" if test "x$TOOLCHAIN_TYPE" = xsolstudio; then - JDKLIB_LIBS="$JDKLIB_LIBS -lc" + $2JDKLIB_LIBS="[$]$2JDKLIB_LIBS -lc" fi - # When building a buildjdk, it's always only the server variant - OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} \ - -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" fi - OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_JDKLIB}" - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${EXTRA_LDFLAGS_JDK}" + # Set $2JVM_LIBS (per os) + if test "x$OPENJDK_$1_OS" = xlinux; then + $2JVM_LIBS="[$]$2JVM_LIBS -lm -ldl -lpthread" + elif test "x$OPENJDK_$1_OS" = xsolaris; then + # FIXME: This hard-coded path is not really proper. + if test "x$OPENJDK_$1_CPU" = xx86_64; then + $2SOLARIS_LIBM_LIBS="/usr/lib/amd64/libm.so.1" + elif test "x$OPENJDK_$1_CPU" = xsparcv9; then + $2SOLARIS_LIBM_LIBS="/usr/lib/sparcv9/libm.so.1" + fi + $2JVM_LIBS="[$]$2JVM_LIBS -lsocket -lsched -ldl $SOLARIS_LIBM_LIBS -lCrun \ + -lthread -ldoor -lc -ldemangle -lnsl -lkstat -lrt" + elif test "x$OPENJDK_$1_OS" = xmacosx; then + $2JVM_LIBS="[$]$2JVM_LIBS -lm" + elif test "x$OPENJDK_$1_OS" = xaix; then + $2JVM_LIBS="[$]$2JVM_LIBS -Wl,-lC_r -lm -ldl -lpthread" + elif test "x$OPENJDK_$1_OS" = xbsd; then + $2JVM_LIBS="[$]$2JVM_LIBS -lm" + elif test "x$OPENJDK_$1_OS" = xwindows; then + $2JVM_LIBS="[$]$2JVM_LIBS kernel32.lib user32.lib gdi32.lib winspool.lib \ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib \ + wsock32.lib winmm.lib version.lib psapi.lib" + fi - AC_SUBST(LDFLAGS_JDKLIB) - AC_SUBST(LDFLAGS_JDKEXE) - AC_SUBST(OPENJDK_BUILD_LDFLAGS_JDKLIB) - AC_SUBST(OPENJDK_BUILD_LDFLAGS_JDKEXE) - AC_SUBST(JDKLIB_LIBS) - AC_SUBST(JDKEXE_LIBS) - AC_SUBST(LDFLAGS_CXX_JDK) - AC_SUBST(LDFLAGS_HASH_STYLE) + # Set $2JVM_ASFLAGS + if test "x$OPENJDK_$1_OS" = xlinux; then + if test "x$OPENJDK_$1_CPU" = xx86; then + $2JVM_ASFLAGS="[$]$2JVM_ASFLAGS -march=i586" + fi + elif test "x$OPENJDK_$1_OS" = xmacosx; then + $2JVM_ASFLAGS="[$]$2JVM_ASFLAGS -x assembler-with-cpp -mno-omit-leaf-frame-pointer -mstack-alignment=16" + fi - LDFLAGS_TESTLIB="$LDFLAGS_JDKLIB" - LDFLAGS_TESTEXE="$LDFLAGS_JDKEXE" + $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${$2EXTRA_LDFLAGS_JDK}" + + AC_SUBST($2LDFLAGS_JDKLIB) + AC_SUBST($2LDFLAGS_JDKEXE) + AC_SUBST($2JDKLIB_LIBS) + AC_SUBST($2JDKEXE_LIBS) + AC_SUBST($2LDFLAGS_CXX_JDK) + AC_SUBST($2LDFLAGS_HASH_STYLE) + + AC_SUBST($2JVM_CFLAGS) + AC_SUBST($2JVM_LDFLAGS) + AC_SUBST($2JVM_ASFLAGS) + AC_SUBST($2JVM_LIBS) - AC_SUBST(LDFLAGS_TESTLIB) - AC_SUBST(LDFLAGS_TESTEXE) ]) # FLAGS_C_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [ARGUMENT], IF_TRUE: [RUN-IF-TRUE], diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 0c503ce2be9..d97c4b4ebc7 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -651,7 +651,21 @@ JOBS MEMORY_SIZE NUM_CORES ENABLE_INTREE_EC +JVM_VARIANT_CORE +JVM_VARIANT_ZEROSHARK +JVM_VARIANT_ZERO +JVM_VARIANT_HOTSPOT +JVM_VARIANT_MINIMAL1 +JVM_VARIANT_CLIENT +JVM_VARIANT_SERVER +JVM_VARIANTS_COMMA +TEST_IN_BUILD HOTSPOT_MAKE_ARGS +MACOSX_UNIVERSAL +DEBUG_CLASSFILES +FASTDEBUG +VARIANT +USE_NEW_HOTSPOT_BUILD LIBZIP_CAN_USE_MMAP LIBDL LIBM @@ -687,6 +701,15 @@ LIBCXX STATIC_CXX_SETTING FIXPATH_DETACH_FLAG FIXPATH +VALID_JVM_FEATURES +JVM_FEATURES_custom +JVM_FEATURES_zeroshark +JVM_FEATURES_zero +JVM_FEATURES_minimal +JVM_FEATURES_core +JVM_FEATURES_client +JVM_FEATURES_server +INCLUDE_DTRACE GCOV_ENABLED STRIP_POLICY DEBUG_BINARIES @@ -702,22 +725,35 @@ COMPILER_SUPPORTS_TARGET_BITS_FLAG ZERO_ARCHFLAG LDFLAGS_TESTEXE LDFLAGS_TESTLIB -LDFLAGS_HASH_STYLE -LDFLAGS_CXX_JDK -JDKEXE_LIBS -JDKLIB_LIBS -OPENJDK_BUILD_LDFLAGS_JDKEXE -OPENJDK_BUILD_LDFLAGS_JDKLIB -LDFLAGS_JDKEXE -LDFLAGS_JDKLIB CXXFLAGS_TESTEXE CXXFLAGS_TESTLIB CFLAGS_TESTEXE CFLAGS_TESTLIB +OPENJDK_BUILD_JVM_LIBS +OPENJDK_BUILD_JVM_ASFLAGS +OPENJDK_BUILD_JVM_LDFLAGS +OPENJDK_BUILD_JVM_CFLAGS +OPENJDK_BUILD_LDFLAGS_HASH_STYLE +OPENJDK_BUILD_LDFLAGS_CXX_JDK +OPENJDK_BUILD_JDKEXE_LIBS +OPENJDK_BUILD_JDKLIB_LIBS +OPENJDK_BUILD_LDFLAGS_JDKEXE +OPENJDK_BUILD_LDFLAGS_JDKLIB OPENJDK_BUILD_CXXFLAGS_JDKEXE OPENJDK_BUILD_CXXFLAGS_JDKLIB OPENJDK_BUILD_CFLAGS_JDKEXE OPENJDK_BUILD_CFLAGS_JDKLIB +OPENJDK_BUILD_CXXSTD_CXXFLAG +JVM_LIBS +JVM_ASFLAGS +JVM_LDFLAGS +JVM_CFLAGS +LDFLAGS_HASH_STYLE +LDFLAGS_CXX_JDK +JDKEXE_LIBS +JDKLIB_LIBS +LDFLAGS_JDKEXE +LDFLAGS_JDKLIB CXXFLAGS_JDKEXE CXXFLAGS_JDKLIB CFLAGS_JDKEXE @@ -726,16 +762,21 @@ MACOSX_VERSION_MIN NO_LIFETIME_DSE_CFLAG NO_NULL_POINTER_CHECK_CFLAG CXXSTD_CXXFLAG +CXX_O_FLAG_SIZE CXX_O_FLAG_NONE CXX_O_FLAG_DEBUG CXX_O_FLAG_NORM CXX_O_FLAG_HI CXX_O_FLAG_HIGHEST +CXX_O_FLAG_HIGHEST_JVM +C_O_FLAG_SIZE C_O_FLAG_NONE C_O_FLAG_DEBUG C_O_FLAG_NORM C_O_FLAG_HI C_O_FLAG_HIGHEST +C_O_FLAG_HIGHEST_JVM +JVM_CFLAGS_SYMBOLS CXXFLAGS_DEBUG_SYMBOLS CFLAGS_DEBUG_SYMBOLS CXX_FLAG_DEPS @@ -747,6 +788,7 @@ SET_SHARED_LIBRARY_ORIGIN SET_EXECUTABLE_ORIGIN CXX_FLAG_REORDER C_FLAG_REORDER +JVM_RCFLAGS RC_FLAGS AR_OUT_OPTION LD_OUT_OPTION @@ -759,6 +801,7 @@ COMPILER_COMMAND_FILE_FLAG COMPILER_TARGET_BITS_FLAG JT_HOME JTREGEXE +HOTSPOT_TOOLCHAIN_TYPE USING_BROKEN_SUSE_LD PACKAGE_PATH USE_CLANG @@ -821,6 +864,9 @@ VS_PATH CYGWIN_LINK SYSROOT_LDFLAGS SYSROOT_CFLAGS +EXTRA_LDFLAGS +EXTRA_CXXFLAGS +EXTRA_CFLAGS LEGACY_EXTRA_LDFLAGS LEGACY_EXTRA_CXXFLAGS LEGACY_EXTRA_CFLAGS @@ -877,12 +923,12 @@ VERSION_MINOR VERSION_MAJOR MACOSX_BUNDLE_ID_BASE MACOSX_BUNDLE_NAME_BASE +HOTSPOT_VM_DISTRO COMPANY_NAME JDK_RC_PLATFORM_NAME PRODUCT_SUFFIX PRODUCT_NAME LAUNCHER_NAME -TEST_IN_BUILD JLINK_KEEP_PACKAGED_MODULES COPYRIGHT_YEAR COMPRESS_JARS @@ -904,6 +950,7 @@ XATTR DSYMUTIL IS_GNU_TIME PATCH +DTRACE TIME STAT HG @@ -927,20 +974,10 @@ CONF_NAME SPEC SDKROOT XCODEBUILD -BUILD_VARIANT_RELEASE -DEBUG_CLASSFILES -FASTDEBUG -VARIANT -DEBUG_LEVEL -MACOSX_UNIVERSAL -JVM_VARIANT_CORE -JVM_VARIANT_ZEROSHARK -JVM_VARIANT_ZERO -JVM_VARIANT_MINIMAL1 -JVM_VARIANT_CLIENT -JVM_VARIANT_SERVER +VALID_JVM_VARIANTS JVM_VARIANTS -JVM_INTERPRETER +DEBUG_LEVEL +HOTSPOT_DEBUG_LEVEL JDK_VARIANT SET_OPENJDK USERNAME @@ -949,16 +986,29 @@ ORIGINAL_TOPDIR TOPDIR PATH_SEP ZERO_ARCHDEF -DEFINE_CROSS_COMPILE_ARCH -LP64 -OPENJDK_TARGET_OS_EXPORT_DIR +HOTSPOT_BUILD_CPU_DEFINE +HOTSPOT_BUILD_CPU_ARCH +HOTSPOT_BUILD_CPU +HOTSPOT_BUILD_OS_TYPE +HOTSPOT_BUILD_OS +OPENJDK_BUILD_OS_EXPORT_DIR OPENJDK_BUILD_CPU_JLI_CFLAGS -OPENJDK_TARGET_CPU_JLI_CFLAGS -OPENJDK_TARGET_CPU_OSARCH -OPENJDK_TARGET_CPU_ISADIR +OPENJDK_BUILD_CPU_OSARCH +OPENJDK_BUILD_CPU_ISADIR OPENJDK_BUILD_CPU_LIBDIR OPENJDK_BUILD_CPU_LEGACY_LIB OPENJDK_BUILD_CPU_LEGACY +HOTSPOT_TARGET_CPU_DEFINE +HOTSPOT_TARGET_CPU_ARCH +HOTSPOT_TARGET_CPU +HOTSPOT_TARGET_OS_TYPE +HOTSPOT_TARGET_OS +DEFINE_CROSS_COMPILE_ARCH +LP64 +OPENJDK_TARGET_OS_EXPORT_DIR +OPENJDK_TARGET_CPU_JLI_CFLAGS +OPENJDK_TARGET_CPU_OSARCH +OPENJDK_TARGET_CPU_ISADIR OPENJDK_TARGET_CPU_LIBDIR OPENJDK_TARGET_CPU_LEGACY_LIB OPENJDK_TARGET_CPU_LEGACY @@ -1088,10 +1138,9 @@ with_target_bits enable_openjdk_only with_custom_make_dir with_jdk_variant -with_jvm_interpreter -with_jvm_variants enable_debug with_debug_level +with_jvm_variants with_devkit with_sys_root with_sysroot @@ -1107,7 +1156,6 @@ with_cacerts_file enable_unlimited_crypto with_copyright_year enable_keep_packaged_modules -enable_hotspot_test_in_build with_milestone with_update_version with_user_release_suffix @@ -1147,6 +1195,9 @@ with_native_debug_symbols enable_debug_symbols enable_zip_debug_info enable_native_coverage +enable_dtrace +with_jvm_features +with_jvm_interpreter with_stdc__lib with_msvcr_dll with_msvcp_dll @@ -1172,6 +1223,8 @@ with_lcms with_dxsdk with_dxsdk_lib with_dxsdk_include +enable_new_hotspot_build +enable_hotspot_test_in_build with_num_cores with_memory_size with_jobs @@ -1244,6 +1297,7 @@ READELF HG STAT TIME +DTRACE PATCH DSYMUTIL XATTR @@ -1923,8 +1977,6 @@ Optional Features: Enable unlimited crypto policy [disabled] --disable-keep-packaged-modules Do not keep packaged modules in jdk image [enable] - --enable-hotspot-test-in-build - run the Queens test after Hotspot build [disabled] --enable-static-build enable static library build [disabled] --disable-warnings-as-errors do not consider native warnings to be an error @@ -1936,10 +1988,18 @@ Optional Features: --enable-native-coverage enable native compilation with code coverage data[disabled] + --enable-dtrace[=yes/no/auto] + enable dtrace. Default is auto, where dtrace is + enabled if all dependencies are present. --disable-freetype-bundling disable bundling of the freetype library with the build result [enabled on Windows or when using --with-freetype, disabled otherwise] + --disable-new-hotspot-build + disable the new hotspot build system (use the old) + [enabled] + --enable-hotspot-test-in-build + run the Queens test after Hotspot build [disabled] --enable-sjavac use sjavac to do fast incremental compiles [disabled] --disable-javac-server disable javac server [enabled] @@ -1959,11 +2019,11 @@ Optional Packages: --with-custom-make-dir Deprecated. Option is kept for backwards compatibility and is ignored --with-jdk-variant JDK variant to build (normal) [normal] - --with-jvm-interpreter JVM interpreter to build (template, cpp) [template] - --with-jvm-variants JVM variants (separated by commas) to build (server, - client, minimal1, zero, zeroshark, core) [server] --with-debug-level set the debug level (release, fastdebug, slowdebug, optimized) [release] + --with-jvm-variants JVM variants (separated by commas) to build + (server,client,minimal,core,zero,zeroshark,custom) + [server] --with-devkit use this devkit for compilers, tools and resources --with-sys-root alias for --with-sysroot for backwards compatability --with-sysroot use this directory as sysroot @@ -2050,6 +2110,10 @@ Optional Packages: --with-native-debug-symbols set the native debug symbol configuration (none, internal, external, zipped) [varying] + --with-jvm-features additional JVM features to enable (separated by + comma), use '--help' to show possible values [none] + --with-jvm-interpreter Deprecated. Option is kept for backwards + compatibility and is ignored --with-stdc++lib=,, force linking of the C++ runtime on Linux to either static or dynamic, default is static with dynamic as @@ -2170,6 +2234,7 @@ Some influential environment variables: HG Override default value for HG STAT Override default value for STAT TIME Override default value for TIME + DTRACE Override default value for DTRACE PATCH Override default value for PATCH DSYMUTIL Override default value for DSYMUTIL XATTR Override default value for XATTR @@ -3969,6 +4034,13 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + +################################################################################ +# $1 - Either BUILD or TARGET to pick the correct OS/CPU variables to check +# conditionals against. +# $2 - Optional prefix for each variable defined. + + # FLAGS_C_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [ARGUMENT], IF_TRUE: [RUN-IF-TRUE], # IF_FALSE: [RUN-IF-FALSE]) # ------------------------------------------------------------ @@ -4093,6 +4165,8 @@ apt_help() { PKGHANDLER_COMMAND="sudo apt-get install libX11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev" ;; ccache) PKGHANDLER_COMMAND="sudo apt-get install ccache" ;; + dtrace) + PKGHANDLER_COMMAND="sudo apt-get install systemtap-sdt-dev" ;; esac } @@ -4162,37 +4236,66 @@ pkgadd_help() { # questions. # -############################################################################### -# Check which interpreter of the JVM we want to build. -# Currently we have: -# template: Template interpreter (the default) -# cpp : C++ interpreter +# All valid JVM features, regardless of platform +VALID_JVM_FEATURES="compiler1 compiler2 zero shark minimal dtrace jvmti jvmci \ + fprof vm-structs jni-check services management all-gcs nmt cds static-build" +# All valid JVM variants +VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom" ############################################################################### -# Check which variants of the JVM that we want to build. -# Currently we have: -# server: normal interpreter and a C2 or tiered C1/C2 compiler -# client: normal interpreter and C1 (no C2 compiler) (only 32-bit platforms) -# minimal1: reduced form of client with optional VM services and features stripped out -# zero: no machine code interpreter, no compiler -# zeroshark: zero interpreter and shark/llvm compiler backend -# core: interpreter only, no compiler (only works on some platforms) - - - -############################################################################### -# Setup legacy vars/targets and new vars to deal with different debug levels. +# Check if the specified JVM variant should be built. To be used in shell if +# constructs, like this: +# if HOTSPOT_CHECK_JVM_VARIANT(server); then # -# release: no debug information, all optimizations, no asserts. -# optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'. -# fastdebug: debug information (-g), all optimizations, all asserts -# slowdebug: debug information (-g), no optimizations, all asserts +# Only valid to use after HOTSPOT_SETUP_JVM_VARIANTS has setup variants. + +# Definition kept in one line to allow inlining in if statements. +# Additional [] needed to keep m4 from mangling shell constructs. + + +############################################################################### +# Check if the specified JVM features are explicitly enabled. To be used in +# shell if constructs, like this: +# if HOTSPOT_CHECK_JVM_FEATURE(jvmti); then +# +# Only valid to use after HOTSPOT_SETUP_JVM_FEATURES has setup features. + +# Definition kept in one line to allow inlining in if statements. +# Additional [] needed to keep m4 from mangling shell constructs. + + +############################################################################### +# Check which variants of the JVM that we want to build. Available variants are: +# server: normal interpreter, and a tiered C1/C2 compiler +# client: normal interpreter, and C1 (no C2 compiler) +# minimal: reduced form of client with optional features stripped out +# core: normal interpreter only, no compiler +# zero: C++ based interpreter only, no compiler +# zeroshark: C++ based interpreter, and a llvm-based compiler +# custom: baseline JVM with no default features # +############################################################################### +# Check if dtrace should be enabled and has all prerequisites present. +# +############################################################################### +# Set up all JVM features for each JVM variant. +# + + +############################################################################### +# Validate JVM features once all setup is complete, including custom setup. +# + + +############################################################################### +# Support for old hotspot build. Remove once new hotspot build has proven +# to work satisfactory. +# # @@ -4529,7 +4632,7 @@ pkgadd_help() { # -# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -4613,7 +4716,7 @@ pkgadd_help() { # -# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -4664,6 +4767,9 @@ pkgadd_help() { # +# $1 - Either TARGET or BUILD to setup the variables for. + + #%%% Build and target systems %%% @@ -4950,7 +5056,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1458755892 +DATE_WHEN_GENERATED=1460103573 ############################################################################### # @@ -4975,6 +5081,13 @@ DATE_WHEN_GENERATED=1458755892 TOOLCHAIN_DESCRIPTION=${!toolchain_var_name} $PRINTF " %-10s %s\n" $toolchain "$TOOLCHAIN_DESCRIPTION" done + $PRINTF "\n" + + # Print available jvm features + $PRINTF "The following JVM features are available as arguments to --with-jvm-features.\n" + $PRINTF "Which are valid to use depends on the target platform.\n " + $PRINTF "%s " $VALID_JVM_FEATURES + $PRINTF "\n" # And now exit directly exit 0 @@ -15215,6 +15328,7 @@ $as_echo "$COMPILE_TYPE" >&6; } + # Also store the legacy naming of the cpu. # Ie i586 and amd64 instead of x86 and x86_64 OPENJDK_TARGET_CPU_LEGACY="$OPENJDK_TARGET_CPU" @@ -15245,37 +15359,6 @@ $as_echo "$COMPILE_TYPE" >&6; } fi - # Now do the same for OPENJDK_BUILD_CPU... - # Also store the legacy naming of the cpu. - # Ie i586 and amd64 instead of x86 and x86_64 - OPENJDK_BUILD_CPU_LEGACY="$OPENJDK_BUILD_CPU" - if test "x$OPENJDK_BUILD_CPU" = xx86; then - OPENJDK_BUILD_CPU_LEGACY="i586" - elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then - # On all platforms except MacOSX replace x86_64 with amd64. - OPENJDK_BUILD_CPU_LEGACY="amd64" - fi - - - # And the second legacy naming of the cpu. - # Ie i386 and amd64 instead of x86 and x86_64. - OPENJDK_BUILD_CPU_LEGACY_LIB="$OPENJDK_BUILD_CPU" - if test "x$OPENJDK_BUILD_CPU" = xx86; then - OPENJDK_BUILD_CPU_LEGACY_LIB="i386" - elif test "x$OPENJDK_BUILD_CPU" = xx86_64; then - OPENJDK_BUILD_CPU_LEGACY_LIB="amd64" - fi - - - # This is the name of the cpu (but using i386 and amd64 instead of - # x86 and x86_64, respectively), preceeded by a /, to be used when - # locating libraries. On macosx, it's empty, though. - OPENJDK_BUILD_CPU_LIBDIR="/$OPENJDK_BUILD_CPU_LEGACY_LIB" - if test "x$OPENJDK_BUILD_OS" = xmacosx; then - OPENJDK_BUILD_CPU_LIBDIR="" - fi - - # OPENJDK_TARGET_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to # /amd64 or /sparcv9. This string is appended to some library paths, like this: # /usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libexample.so @@ -15318,6 +15401,140 @@ $as_echo "$COMPILE_TYPE" >&6; } fi + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + OPENJDK_TARGET_OS_EXPORT_DIR=macosx + else + OPENJDK_TARGET_OS_EXPORT_DIR=${OPENJDK_TARGET_OS_TYPE} + fi + + + if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + A_LP64="LP64:=" + # -D_LP64=1 is only set on linux and mac. Setting on windows causes diff in + # unpack200.exe + if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xmacosx; then + OPENJDK_TARGET_ADD_LP64="-D_LP64=1" + fi + fi + LP64=$A_LP64 + + + if test "x$COMPILE_TYPE" = "xcross"; then + # FIXME: ... or should this include reduced builds..? + DEFINE_CROSS_COMPILE_ARCH="CROSS_COMPILE_ARCH:=$OPENJDK_TARGET_CPU_LEGACY" + else + DEFINE_CROSS_COMPILE_ARCH="" + fi + + + # Convert openjdk platform names to hotspot names + + HOTSPOT_TARGET_OS=${OPENJDK_TARGET_OS} + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + HOTSPOT_TARGET_OS=bsd + fi + + + HOTSPOT_TARGET_OS_TYPE=${OPENJDK_TARGET_OS_TYPE} + if test "x$OPENJDK_TARGET_OS_TYPE" = xunix; then + HOTSPOT_TARGET_OS_TYPE=posix + fi + + + HOTSPOT_TARGET_CPU=${OPENJDK_TARGET_CPU} + if test "x$OPENJDK_TARGET_CPU" = xx86; then + HOTSPOT_TARGET_CPU=x86_32 + elif test "x$OPENJDK_TARGET_CPU" = xsparcv9; then + HOTSPOT_TARGET_CPU=sparc + elif test "x$OPENJDK_TARGET_CPU" = xppc64; then + HOTSPOT_TARGET_CPU=ppc_64 + fi + + + # This is identical with OPENJDK_*, but define anyway for consistency. + HOTSPOT_TARGET_CPU_ARCH=${OPENJDK_TARGET_CPU_ARCH} + + + # Setup HOTSPOT_TARGET_CPU_DEFINE + if test "x$OPENJDK_TARGET_CPU" = xx86; then + HOTSPOT_TARGET_CPU_DEFINE=IA32 + elif test "x$OPENJDK_TARGET_CPU" = xx86_64; then + HOTSPOT_TARGET_CPU_DEFINE=AMD64 + elif test "x$OPENJDK_TARGET_CPU" = xsparcv9; then + HOTSPOT_TARGET_CPU_DEFINE=SPARC + elif test "x$OPENJDK_TARGET_CPU" = xaarch64; then + HOTSPOT_TARGET_CPU_DEFINE=AARCH64 + elif test "x$OPENJDK_TARGET_CPU" = xppc64; then + HOTSPOT_TARGET_CPU_DEFINE=PPC64 + + # The cpu defines below are for zero, we don't support them directly. + elif test "x$OPENJDK_TARGET_CPU" = xsparc; then + HOTSPOT_TARGET_CPU_DEFINE=SPARC + elif test "x$OPENJDK_TARGET_CPU" = xppc; then + HOTSPOT_TARGET_CPU_DEFINE=PPC32 + elif test "x$OPENJDK_TARGET_CPU" = xs390; then + HOTSPOT_TARGET_CPU_DEFINE=S390 + elif test "x$OPENJDK_TARGET_CPU" = ss390x; then + HOTSPOT_TARGET_CPU_DEFINE=S390 + fi + + + + + # Also store the legacy naming of the cpu. + # Ie i586 and amd64 instead of x86 and x86_64 + OPENJDK_BUILD_CPU_LEGACY="$OPENJDK_BUILD_CPU" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_CPU_LEGACY="i586" + elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then + # On all platforms except MacOSX replace x86_64 with amd64. + OPENJDK_BUILD_CPU_LEGACY="amd64" + fi + + + # And the second legacy naming of the cpu. + # Ie i386 and amd64 instead of x86 and x86_64. + OPENJDK_BUILD_CPU_LEGACY_LIB="$OPENJDK_BUILD_CPU" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_CPU_LEGACY_LIB="i386" + elif test "x$OPENJDK_BUILD_CPU" = xx86_64; then + OPENJDK_BUILD_CPU_LEGACY_LIB="amd64" + fi + + + # This is the name of the cpu (but using i386 and amd64 instead of + # x86 and x86_64, respectively), preceeded by a /, to be used when + # locating libraries. On macosx, it's empty, though. + OPENJDK_BUILD_CPU_LIBDIR="/$OPENJDK_BUILD_CPU_LEGACY_LIB" + if test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_CPU_LIBDIR="" + fi + + + # OPENJDK_BUILD_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to + # /amd64 or /sparcv9. This string is appended to some library paths, like this: + # /usr/lib${OPENJDK_BUILD_CPU_ISADIR}/libexample.so + OPENJDK_BUILD_CPU_ISADIR="" + if test "x$OPENJDK_BUILD_OS" = xsolaris; then + if test "x$OPENJDK_BUILD_CPU" = xx86_64; then + OPENJDK_BUILD_CPU_ISADIR="/amd64" + elif test "x$OPENJDK_BUILD_CPU" = xsparcv9; then + OPENJDK_BUILD_CPU_ISADIR="/sparcv9" + fi + fi + + + # Setup OPENJDK_BUILD_CPU_OSARCH, which is used to set the os.arch Java system property + OPENJDK_BUILD_CPU_OSARCH="$OPENJDK_BUILD_CPU" + if test "x$OPENJDK_BUILD_OS" = xlinux && test "x$OPENJDK_BUILD_CPU" = xx86; then + # On linux only, we replace x86 with i386. + OPENJDK_BUILD_CPU_OSARCH="i386" + elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then + # On all platforms except macosx, we replace x86_64 with amd64. + OPENJDK_BUILD_CPU_OSARCH="amd64" + fi + + OPENJDK_BUILD_CPU_JLI="$OPENJDK_BUILD_CPU" if test "x$OPENJDK_BUILD_CPU" = xx86; then OPENJDK_BUILD_CPU_JLI="i386" @@ -15336,47 +15553,90 @@ $as_echo "$COMPILE_TYPE" >&6; } fi - if test "x$OPENJDK_TARGET_OS" = xmacosx; then - OPENJDK_TARGET_OS_EXPORT_DIR=macosx + if test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_OS_EXPORT_DIR=macosx else - OPENJDK_TARGET_OS_EXPORT_DIR=${OPENJDK_TARGET_OS_TYPE} + OPENJDK_BUILD_OS_EXPORT_DIR=${OPENJDK_BUILD_OS_TYPE} fi - if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then A_LP64="LP64:=" # -D_LP64=1 is only set on linux and mac. Setting on windows causes diff in # unpack200.exe - if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xmacosx; then - ADD_LP64="-D_LP64=1" - fi - fi - LP64=$A_LP64 - - if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then if test "x$OPENJDK_BUILD_OS" = xlinux || test "x$OPENJDK_BUILD_OS" = xmacosx; then OPENJDK_BUILD_ADD_LP64="-D_LP64=1" fi fi + LP64=$A_LP64 + if test "x$COMPILE_TYPE" = "xcross"; then # FIXME: ... or should this include reduced builds..? - DEFINE_CROSS_COMPILE_ARCH="CROSS_COMPILE_ARCH:=$OPENJDK_TARGET_CPU_LEGACY" + DEFINE_CROSS_COMPILE_ARCH="CROSS_COMPILE_ARCH:=$OPENJDK_BUILD_CPU_LEGACY" else DEFINE_CROSS_COMPILE_ARCH="" fi - # ZERO_ARCHDEF is used to enable architecture-specific code - case "${OPENJDK_TARGET_CPU}" in - ppc) ZERO_ARCHDEF=PPC32 ;; - ppc64) ZERO_ARCHDEF=PPC64 ;; - s390*) ZERO_ARCHDEF=S390 ;; - sparc*) ZERO_ARCHDEF=SPARC ;; - x86_64*) ZERO_ARCHDEF=AMD64 ;; - x86) ZERO_ARCHDEF=IA32 ;; - *) ZERO_ARCHDEF=$(echo "${OPENJDK_TARGET_CPU_LEGACY_LIB}" | tr a-z A-Z) - esac + # Convert openjdk platform names to hotspot names + + HOTSPOT_BUILD_OS=${OPENJDK_BUILD_OS} + if test "x$OPENJDK_BUILD_OS" = xmacosx; then + HOTSPOT_BUILD_OS=bsd + fi + + + HOTSPOT_BUILD_OS_TYPE=${OPENJDK_BUILD_OS_TYPE} + if test "x$OPENJDK_BUILD_OS_TYPE" = xunix; then + HOTSPOT_BUILD_OS_TYPE=posix + fi + + + HOTSPOT_BUILD_CPU=${OPENJDK_BUILD_CPU} + if test "x$OPENJDK_BUILD_CPU" = xx86; then + HOTSPOT_BUILD_CPU=x86_32 + elif test "x$OPENJDK_BUILD_CPU" = xsparcv9; then + HOTSPOT_BUILD_CPU=sparc + elif test "x$OPENJDK_BUILD_CPU" = xppc64; then + HOTSPOT_BUILD_CPU=ppc_64 + fi + + + # This is identical with OPENJDK_*, but define anyway for consistency. + HOTSPOT_BUILD_CPU_ARCH=${OPENJDK_BUILD_CPU_ARCH} + + + # Setup HOTSPOT_BUILD_CPU_DEFINE + if test "x$OPENJDK_BUILD_CPU" = xx86; then + HOTSPOT_BUILD_CPU_DEFINE=IA32 + elif test "x$OPENJDK_BUILD_CPU" = xx86_64; then + HOTSPOT_BUILD_CPU_DEFINE=AMD64 + elif test "x$OPENJDK_BUILD_CPU" = xsparcv9; then + HOTSPOT_BUILD_CPU_DEFINE=SPARC + elif test "x$OPENJDK_BUILD_CPU" = xaarch64; then + HOTSPOT_BUILD_CPU_DEFINE=AARCH64 + elif test "x$OPENJDK_BUILD_CPU" = xppc64; then + HOTSPOT_BUILD_CPU_DEFINE=PPC64 + + # The cpu defines below are for zero, we don't support them directly. + elif test "x$OPENJDK_BUILD_CPU" = xsparc; then + HOTSPOT_BUILD_CPU_DEFINE=SPARC + elif test "x$OPENJDK_BUILD_CPU" = xppc; then + HOTSPOT_BUILD_CPU_DEFINE=PPC32 + elif test "x$OPENJDK_BUILD_CPU" = xs390; then + HOTSPOT_BUILD_CPU_DEFINE=S390 + elif test "x$OPENJDK_BUILD_CPU" = ss390x; then + HOTSPOT_BUILD_CPU_DEFINE=S390 + fi + + + + + # ZERO_ARCHDEF is used to enable architecture-specific code. + # This is used in legacy hotspot build. + ZERO_ARCHDEF="$HOTSPOT_TARGET_CPU_DEFINE" + @@ -15915,98 +16175,6 @@ fi $as_echo "$JDK_VARIANT" >&6; } - -# Check whether --with-jvm-interpreter was given. -if test "${with_jvm_interpreter+set}" = set; then : - withval=$with_jvm_interpreter; -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking which interpreter of the JVM to build" >&5 -$as_echo_n "checking which interpreter of the JVM to build... " >&6; } - if test "x$with_jvm_interpreter" = x; then - JVM_INTERPRETER="template" - else - JVM_INTERPRETER="$with_jvm_interpreter" - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JVM_INTERPRETER" >&5 -$as_echo "$JVM_INTERPRETER" >&6; } - - if test "x$JVM_INTERPRETER" != xtemplate && test "x$JVM_INTERPRETER" != xcpp; then - as_fn_error $? "The available JVM interpreters are: template, cpp" "$LINENO" 5 - fi - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variants of the JVM to build" >&5 -$as_echo_n "checking which variants of the JVM to build... " >&6; } - -# Check whether --with-jvm-variants was given. -if test "${with_jvm_variants+set}" = set; then : - withval=$with_jvm_variants; -fi - - - if test "x$with_jvm_variants" = x; then - with_jvm_variants="server" - fi - - JVM_VARIANTS=",$with_jvm_variants," - TEST_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,//' -e 's/client,//' -e 's/minimal1,//' -e 's/zero,//' -e 's/zeroshark,//' -e 's/core,//'` - - if test "x$TEST_VARIANTS" != "x,"; then - as_fn_error $? "The available JVM variants are: server, client, minimal1, zero, zeroshark, core" "$LINENO" 5 - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_jvm_variants" >&5 -$as_echo "$with_jvm_variants" >&6; } - - JVM_VARIANT_SERVER=`$ECHO "$JVM_VARIANTS" | $SED -e '/,server,/!s/.*/false/g' -e '/,server,/s/.*/true/g'` - JVM_VARIANT_CLIENT=`$ECHO "$JVM_VARIANTS" | $SED -e '/,client,/!s/.*/false/g' -e '/,client,/s/.*/true/g'` - JVM_VARIANT_MINIMAL1=`$ECHO "$JVM_VARIANTS" | $SED -e '/,minimal1,/!s/.*/false/g' -e '/,minimal1,/s/.*/true/g'` - JVM_VARIANT_ZERO=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zero,/!s/.*/false/g' -e '/,zero,/s/.*/true/g'` - JVM_VARIANT_ZEROSHARK=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zeroshark,/!s/.*/false/g' -e '/,zeroshark,/s/.*/true/g'` - JVM_VARIANT_CORE=`$ECHO "$JVM_VARIANTS" | $SED -e '/,core,/!s/.*/false/g' -e '/,core,/s/.*/true/g'` - - if test "x$JVM_VARIANT_CLIENT" = xtrue; then - if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then - as_fn_error $? "You cannot build a client JVM for a 64-bit machine." "$LINENO" 5 - fi - fi - if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then - if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then - as_fn_error $? "You cannot build a minimal JVM for a 64-bit machine." "$LINENO" 5 - fi - fi - - # Replace the commas with AND for use in the build directory name. - ANDED_JVM_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/^,//' -e 's/,$//' -e 's/,/AND/g'` - COUNT_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,/1/' -e 's/client,/1/' -e 's/minimal1,/1/' -e 's/zero,/1/' -e 's/zeroshark,/1/' -e 's/core,/1/'` - if test "x$COUNT_VARIANTS" != "x,1"; then - BUILDING_MULTIPLE_JVM_VARIANTS=yes - else - BUILDING_MULTIPLE_JVM_VARIANTS=no - fi - - if test "x$JVM_VARIANT_ZERO" = xtrue && test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = xyes; then - as_fn_error $? "You cannot build multiple variants with zero." "$LINENO" 5 - fi - - - - - - - - - - if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then - MACOSX_UNIVERSAL="true" - fi - - - - DEBUG_LEVEL="release" { $as_echo "$as_me:${as_lineno-$LINENO}: checking which debug level to use" >&5 $as_echo_n "checking which debug level to use... " >&6; } @@ -16042,106 +16210,89 @@ $as_echo "$DEBUG_LEVEL" >&6; } as_fn_error $? "Allowed debug levels are: release, fastdebug, slowdebug and optimized" "$LINENO" 5 fi + # Translate DEBUG_LEVEL to debug level used by Hotspot + HOTSPOT_DEBUG_LEVEL="$DEBUG_LEVEL" + if test "x$DEBUG_LEVEL" = xrelease; then + HOTSPOT_DEBUG_LEVEL="product" + elif test "x$DEBUG_LEVEL" = xslowdebug; then + HOTSPOT_DEBUG_LEVEL="debug" + fi - case $DEBUG_LEVEL in - release ) - VARIANT="OPT" - FASTDEBUG="false" - DEBUG_CLASSFILES="false" - BUILD_VARIANT_RELEASE="" - HOTSPOT_DEBUG_LEVEL="product" - HOTSPOT_EXPORT="product" - ;; - fastdebug ) - VARIANT="DBG" - FASTDEBUG="true" - DEBUG_CLASSFILES="true" - BUILD_VARIANT_RELEASE="-fastdebug" - HOTSPOT_DEBUG_LEVEL="fastdebug" - HOTSPOT_EXPORT="fastdebug" - ;; - slowdebug ) - VARIANT="DBG" - FASTDEBUG="false" - DEBUG_CLASSFILES="true" - BUILD_VARIANT_RELEASE="-debug" - HOTSPOT_DEBUG_LEVEL="debug" - HOTSPOT_EXPORT="debug" - ;; - optimized ) - VARIANT="OPT" - FASTDEBUG="false" - DEBUG_CLASSFILES="false" - BUILD_VARIANT_RELEASE="-optimized" - HOTSPOT_DEBUG_LEVEL="optimized" - HOTSPOT_EXPORT="optimized" - ;; - esac - - # The debug level 'optimized' is a little special because it is currently only - # applicable to the HotSpot build where it means to build a completely - # optimized version of the VM without any debugging code (like for the - # 'release' debug level which is called 'product' in the HotSpot build) but - # with the exception that it can contain additional code which is otherwise - # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to - # test new and/or experimental features which are not intended for customer - # shipment. Because these new features need to be tested and benchmarked in - # real world scenarios, we want to build the containing JDK at the 'release' - # debug level. if test "x$DEBUG_LEVEL" = xoptimized; then + # The debug level 'optimized' is a little special because it is currently only + # applicable to the HotSpot build where it means to build a completely + # optimized version of the VM without any debugging code (like for the + # 'release' debug level which is called 'product' in the HotSpot build) but + # with the exception that it can contain additional code which is otherwise + # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to + # test new and/or experimental features which are not intended for customer + # shipment. Because these new features need to be tested and benchmarked in + # real world scenarios, we want to build the containing JDK at the 'release' + # debug level. DEBUG_LEVEL="release" fi - ##### - # Generate the legacy makefile targets for hotspot. - # The hotspot api for selecting the build artifacts, really, needs to be improved. - # JDK-7195896 will fix this on the hotspot side by using the JVM_VARIANT_* variables to - # determine what needs to be built. All we will need to set here is all_product, all_fastdebug etc - # But until then ... - HOTSPOT_TARGET="" - if test "x$JVM_VARIANT_SERVER" = xtrue; then - HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL} " + + + + +# Check whether --with-jvm-variants was given. +if test "${with_jvm_variants+set}" = set; then : + withval=$with_jvm_variants; +fi + + + if test "x$with_jvm_variants" = x; then + with_jvm_variants="server" + fi + JVM_VARIANTS_OPT="$with_jvm_variants" + + # Has the user listed more than one variant? + # Additional [] needed to keep m4 from mangling shell constructs. + if [[ "$JVM_VARIANTS_OPT" =~ "," ]] ; then + BUILDING_MULTIPLE_JVM_VARIANTS=true + else + BUILDING_MULTIPLE_JVM_VARIANTS=false + fi + # Replace the commas with AND for use in the build directory name. + JVM_VARIANTS_WITH_AND=`$ECHO "$JVM_VARIANTS_OPT" | $SED -e 's/,/AND/g'` + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variants of the JVM to build" >&5 +$as_echo_n "checking which variants of the JVM to build... " >&6; } + # JVM_VARIANTS is a space-separated list. + # Also use minimal, not minimal1 (which is kept for backwards compatibility). + JVM_VARIANTS=`$ECHO $JVM_VARIANTS_OPT | $SED -e 's/,/ /g' -e 's/minimal1/minimal/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JVM_VARIANTS" >&5 +$as_echo "$JVM_VARIANTS" >&6; } + + # Check that the selected variants are valid + + # grep filter function inspired by a comment to http://stackoverflow.com/a/1617326 + INVALID_VARIANTS=`$GREP -Fvx "${VALID_JVM_VARIANTS// /$'\n'}" <<< "${JVM_VARIANTS// /$'\n'}"` + if test "x$INVALID_VARIANTS" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Unknown variant(s) specified: $INVALID_VARIANTS" >&5 +$as_echo "$as_me: Unknown variant(s) specified: $INVALID_VARIANTS" >&6;} + as_fn_error $? "The available JVM variants are: $VALID_JVM_VARIANTS" "$LINENO" 5 fi - if test "x$JVM_VARIANT_CLIENT" = xtrue; then - HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}1 " + # All "special" variants share the same output directory ("server") + VALID_MULTIPLE_JVM_VARIANTS="server client minimal" + INVALID_MULTIPLE_VARIANTS=`$GREP -Fvx "${VALID_MULTIPLE_JVM_VARIANTS// /$'\n'}" <<< "${JVM_VARIANTS// /$'\n'}"` + if test "x$INVALID_MULTIPLE_VARIANTS" != x && test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = xtrue; then + as_fn_error $? "You cannot build multiple variants with anything else than $VALID_MULTIPLE_JVM_VARIANTS." "$LINENO" 5 fi - if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then - HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}minimal1 " + + + + if [[ " $JVM_VARIANTS " =~ " zero " ]] || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then + # zero behaves as a platform and rewrites these values. This is really weird. :( + # We are guaranteed that we do not build any other variants when building zero. + HOTSPOT_TARGET_CPU=zero + HOTSPOT_TARGET_CPU_ARCH=zero fi - if test "x$JVM_VARIANT_ZERO" = xtrue; then - HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}zero " - fi - - if test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then - HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}shark " - fi - - if test "x$JVM_VARIANT_CORE" = xtrue; then - HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}core " - fi - - HOTSPOT_TARGET="$HOTSPOT_TARGET docs export_$HOTSPOT_EXPORT" - - # On Macosx universal binaries are produced, but they only contain - # 64 bit intel. This invalidates control of which jvms are built - # from configure, but only server is valid anyway. Fix this - # when hotspot makefiles are rewritten. - if test "x$MACOSX_UNIVERSAL" = xtrue; then - HOTSPOT_TARGET=universal_${HOTSPOT_EXPORT} - fi - - ##### - - - - - - - # With basic setup done, call the custom early hook. @@ -16589,8 +16740,8 @@ $as_echo "$as_me: WARNING: Both SYSROOT and --with-sdk-name are set, only SYSROO if test "x$OPENJDK_BUILD_OS" = "xsolaris"; then - # Add extra search paths on solaris for utilities like ar and as etc... - PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin" + # Add extra search paths on solaris for utilities like ar, as, dtrace etc... + PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin:/usr/sbin" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 @@ -16629,7 +16780,7 @@ $as_echo_n "checking where to store configuration... " >&6; } if test "x${CONF_NAME}" = x; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: in default location" >&5 $as_echo "in default location" >&6; } - CONF_NAME="${OPENJDK_TARGET_OS}-${OPENJDK_TARGET_CPU}-${JDK_VARIANT}-${ANDED_JVM_VARIANTS}-${DEBUG_LEVEL}" + CONF_NAME="${OPENJDK_TARGET_OS}-${OPENJDK_TARGET_CPU}-${JDK_VARIANT}-${JVM_VARIANTS_WITH_AND}-${DEBUG_LEVEL}" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: in build directory with custom name" >&5 $as_echo "in build directory with custom name" >&6; } @@ -22126,6 +22277,203 @@ $as_echo "$tool_specified" >&6; } + # Publish this variable in the help. + + + if [ -z "${DTRACE+x}" ]; then + # The variable is not set by user, try to locate tool using the code snippet + for ac_prog in dtrace +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_DTRACE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $DTRACE in + [\\/]* | ?:[\\/]*) + ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_DTRACE="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +DTRACE=$ac_cv_path_DTRACE +if test -n "$DTRACE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DTRACE" >&5 +$as_echo "$DTRACE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DTRACE" && break +done + + else + # The variable is set, but is it from the command line or the environment? + + # Try to remove the string !DTRACE! from our list. + try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!DTRACE!/} + if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then + # If it failed, the variable was not from the command line. Ignore it, + # but warn the user (except for BASH, which is always set by the calling BASH). + if test "xDTRACE" != xBASH; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of DTRACE from the environment. Use command line variables instead." >&5 +$as_echo "$as_me: WARNING: Ignoring value of DTRACE from the environment. Use command line variables instead." >&2;} + fi + # Try to locate tool using the code snippet + for ac_prog in dtrace +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_DTRACE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $DTRACE in + [\\/]* | ?:[\\/]*) + ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_DTRACE="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +DTRACE=$ac_cv_path_DTRACE +if test -n "$DTRACE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DTRACE" >&5 +$as_echo "$DTRACE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DTRACE" && break +done + + else + # If it succeeded, then it was overridden by the user. We will use it + # for the tool. + + # First remove it from the list of overridden variables, so we can test + # for unknown variables in the end. + CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var" + + # Check if we try to supply an empty value + if test "x$DTRACE" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool DTRACE= (no value)" >&5 +$as_echo "$as_me: Setting user supplied tool DTRACE= (no value)" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DTRACE" >&5 +$as_echo_n "checking for DTRACE... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 +$as_echo "disabled" >&6; } + else + # Check if the provided tool contains a complete path. + tool_specified="$DTRACE" + tool_basename="${tool_specified##*/}" + if test "x$tool_basename" = "x$tool_specified"; then + # A command without a complete path is provided, search $PATH. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool DTRACE=$tool_basename" >&5 +$as_echo "$as_me: Will search for user supplied tool DTRACE=$tool_basename" >&6;} + # Extract the first word of "$tool_basename", so it can be a program name with args. +set dummy $tool_basename; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_DTRACE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $DTRACE in + [\\/]* | ?:[\\/]*) + ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_DTRACE="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +DTRACE=$ac_cv_path_DTRACE +if test -n "$DTRACE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DTRACE" >&5 +$as_echo "$DTRACE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$DTRACE" = x; then + as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5 + fi + else + # Otherwise we believe it is a complete path. Use it as it is. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool DTRACE=$tool_specified" >&5 +$as_echo "$as_me: Will use user supplied tool DTRACE=$tool_specified" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DTRACE" >&5 +$as_echo_n "checking for DTRACE... " >&6; } + if test ! -x "$tool_specified"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + as_fn_error $? "User supplied tool DTRACE=$tool_specified does not exist or is not executable" "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5 +$as_echo "$tool_specified" >&6; } + fi + fi + fi + + fi + + + + # Publish this variable in the help. @@ -23408,10 +23756,7 @@ fi # Should we build the serviceability agent (SA)? INCLUDE_SA=true - if test "x$JVM_VARIANT_ZERO" = xtrue ; then - INCLUDE_SA=false - fi - if test "x$JVM_VARIANT_ZEROSHARK" = xtrue ; then + if [[ " $JVM_VARIANTS " =~ " zero " ]] || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then INCLUDE_SA=false fi if test "x$OPENJDK_TARGET_OS" = xaix ; then @@ -23473,22 +23818,6 @@ $as_echo "yes (default)" >&6; } - # Control wether Hotspot runs Queens test after build. - # Check whether --enable-hotspot-test-in-build was given. -if test "${enable_hotspot_test_in_build+set}" = set; then : - enableval=$enable_hotspot_test_in_build; -else - enable_hotspot_test_in_build=no -fi - - if test "x$enable_hotspot_test_in_build" = "xyes"; then - TEST_IN_BUILD=true - else - TEST_IN_BUILD=false - fi - - - # Warn user that old version arguments are deprecated. @@ -23539,6 +23868,7 @@ fi + # Override version from arguments # If --with-version-string is set, process it first. It is possible to @@ -30611,6 +30941,10 @@ fi + + + + # The global CFLAGS and LDLAGS variables are used by configure tests and # should include the extra parameters CFLAGS="$EXTRA_CFLAGS" @@ -46738,6 +47072,17 @@ $as_echo "yes" >&6; } fi + # Setup hotspot lecagy names for toolchains + HOTSPOT_TOOLCHAIN_TYPE=$TOOLCHAIN_TYPE + if test "x$TOOLCHAIN_TYPE" = xclang; then + HOTSPOT_TOOLCHAIN_TYPE=gcc + elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then + HOTSPOT_TOOLCHAIN_TYPE=sparcWorks + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + HOTSPOT_TOOLCHAIN_TYPE=visCPP + fi + + # Setup the JTReg Regression Test Harness. @@ -47217,8 +47562,10 @@ $as_echo "no" >&6; } # On Windows, we need to set RC flags. if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then RC_FLAGS="-nologo -l0x409" + JVM_RCFLAGS="-nologo" if test "x$DEBUG_LEVEL" = xrelease; then RC_FLAGS="$RC_FLAGS -DNDEBUG" + JVM_RCFLAGS="$JVM_RCFLAGS -DNDEBUG" fi # The version variables used to create RC_FLAGS may be overridden @@ -47234,9 +47581,20 @@ $as_echo "no" >&6; } -D\"JDK_COPYRIGHT=Copyright \xA9 $COPYRIGHT_YEAR\" \ -D\"JDK_NAME=\$(PRODUCT_NAME) \$(JDK_RC_PLATFORM_NAME) \$(VERSION_MAJOR)\" \ -D\"JDK_FVER=\$(subst .,\$(COMMA),\$(VERSION_NUMBER_FOUR_POSITIONS))\"" + + JVM_RCFLAGS="$JVM_RCFLAGS \ + -D\"HS_BUILD_ID=\$(VERSION_STRING)\" \ + -D\"HS_COMPANY=\$(COMPANY_NAME)\" \ + -D\"JDK_DOTVER=\$(VERSION_NUMBER_FOUR_POSITIONS)\" \ + -D\"HS_COPYRIGHT=Copyright $COPYRIGHT_YEAR\" \ + -D\"HS_NAME=\$(PRODUCT_NAME) \$(VERSION_SHORT)\" \ + -D\"JDK_VER=\$(subst .,\$(COMMA),\$(VERSION_NUMBER_FOUR_POSITIONS))\" \ + -D\"HS_FNAME=jvm.dll\" \ + -D\"HS_INTERNAL_NAME=jvm\"" fi + if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then # silence copyright notice and other headers. COMMON_CCXXFLAGS="$COMMON_CCXXFLAGS -nologo" @@ -47402,6 +47760,10 @@ done CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}" LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}" + JVM_CFLAGS="$JVM_CFLAGS $ADDED_CFLAGS" + JVM_LDFLAGS="$JVM_LDFLAGS $ADDED_LDFLAGS" + JVM_ASFLAGS="$JVM_ASFLAGS $ADDED_CFLAGS" + elif test "x$COMPILE_TYPE" = xreduced; then if test "x$OPENJDK_TARGET_OS_TYPE" = xunix; then # Specify -m if running reduced on unix platforms @@ -47422,8 +47784,17 @@ done CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}" LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}" + JVM_CFLAGS="$JVM_CFLAGS $ADDED_CFLAGS" + JVM_LDFLAGS="$JVM_LDFLAGS $ADDED_LDFLAGS" + JVM_ASFLAGS="$JVM_ASFLAGS $ADDED_CFLAGS" + fi fi + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + JVM_CFLAGS="$JVM_CFLAGS ${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" + JVM_LDFLAGS="$JVM_LDFLAGS ${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" + JVM_ASFLAGS="$JVM_ASFLAGS ${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" + fi # Make compilation sanity check for ac_header in stdio.h @@ -47548,6 +47919,10 @@ $as_echo "$as_me: Retrying with platforms compiler target bits flag to ${COMPILE CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}" LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}" + JVM_CFLAGS="$JVM_CFLAGS $ADDED_CFLAGS" + JVM_LDFLAGS="$JVM_LDFLAGS $ADDED_LDFLAGS" + JVM_ASFLAGS="$JVM_ASFLAGS $ADDED_CFLAGS" + # We have to unset 'ac_cv_sizeof_int_p' first, otherwise AC_CHECK_SIZEOF will use the previously cached value! unset ac_cv_sizeof_int_p @@ -47894,6 +48269,7 @@ $as_echo "$ac_cv_c_bigendian" >&6; } SHARED_LIBRARY_FLAGS ='-undefined dynamic_lookup' else SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG" + JVM_CFLAGS="$JVM_CFLAGS $PICFLAG" fi SET_EXECUTABLE_ORIGIN='-Wl,-rpath,@loader_path/.' SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN" @@ -47919,6 +48295,10 @@ $as_echo "$ac_cv_c_bigendian" >&6; } SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN" SET_SHARED_LIBRARY_NAME='-Wl,-install_name,@rpath/$1' SET_SHARED_LIBRARY_MAPFILE='-Wl,-exported_symbols_list,$1' + + if test "x$STATIC_BUILD" = xfalse; then + JVM_CFLAGS="$JVM_CFLAGS -fPIC" + fi else # Default works for linux, might work on other platforms as well. PICFLAG='-fPIC' @@ -47978,11 +48358,6 @@ $as_echo "$ac_cv_c_bigendian" >&6; } - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - CFLAGS_JDK="${CFLAGS_JDK} -D__solaris__" - CXXFLAGS_JDK="${CXXFLAGS_JDK} -D__solaris__" - CFLAGS_JDKLIB_EXTRA='-xstrconst' - fi # The (cross) compiler is now configured, we can now test capabilities # of the target platform. @@ -48040,6 +48415,22 @@ $as_echo "$ac_cv_c_bigendian" >&6; } + # Debug symbols for JVM_CFLAGS + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -xs" + if test "x$DEBUG_LEVEL" = xslowdebug; then + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -g" + else + # -g0 does not disable inlining, which -g does. + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -g0" + fi + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -Z7 -d2Zi+" + else + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS -g" + fi + + # bounds, memory and behavior checking options if test "x$TOOLCHAIN_TYPE" = xgcc; then case $DEBUG_LEVEL in @@ -48050,7 +48441,7 @@ $as_echo "$ac_cv_c_bigendian" >&6; } # no adjustment ;; slowdebug ) - # FIXME: By adding this to C(XX)FLAGS_DEBUG_OPTIONS it + # FIXME: By adding this to C(XX)FLAGS_DEBUG_OPTIONS/JVM_CFLAGS_SYMBOLS it # get's added conditionally on whether we produce debug symbols or not. # This is most likely not really correct. @@ -48325,40 +48716,59 @@ $as_echo "$supports" >&6; } CFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" CXXFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" + if test "x$STACK_PROTECTOR_CFLAG" != x; then + JVM_CFLAGS_SYMBOLS="$JVM_CFLAGS_SYMBOLS $STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" + fi ;; esac fi + if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + if test "x$DEBUG_LEVEL" != xrelease; then + if test "x$OPENJDK_TARGET_CPU" = xx86_64; then + JVM_CFLAGS="$JVM_CFLAGS -homeparams" + fi + fi + fi + # Optimization levels if test "x$TOOLCHAIN_TYPE" = xsolstudio; then CC_HIGHEST="$CC_HIGHEST -fns -fsimple -fsingle -xbuiltin=%all -xdepend -xrestrict -xlibmil" if test "x$OPENJDK_TARGET_CPU_ARCH" = "xx86"; then # FIXME: seems we always set -xregs=no%frameptr; put it elsewhere more global? + C_O_FLAG_HIGHEST_JVM="-xO4" C_O_FLAG_HIGHEST="-xO4 -Wu,-O4~yz $CC_HIGHEST -xalias_level=basic -xregs=no%frameptr" C_O_FLAG_HI="-xO4 -Wu,-O4~yz -xregs=no%frameptr" C_O_FLAG_NORM="-xO2 -Wu,-O2~yz -xregs=no%frameptr" C_O_FLAG_DEBUG="-xregs=no%frameptr" + C_O_FLAG_DEBUG_JVM="" C_O_FLAG_NONE="-xregs=no%frameptr" + CXX_O_FLAG_HIGHEST_JVM="-xO4" CXX_O_FLAG_HIGHEST="-xO4 -Qoption ube -O4~yz $CC_HIGHEST -xregs=no%frameptr" CXX_O_FLAG_HI="-xO4 -Qoption ube -O4~yz -xregs=no%frameptr" CXX_O_FLAG_NORM="-xO2 -Qoption ube -O2~yz -xregs=no%frameptr" CXX_O_FLAG_DEBUG="-xregs=no%frameptr" + CXX_O_FLAG_DEBUG_JVM="" CXX_O_FLAG_NONE="-xregs=no%frameptr" if test "x$OPENJDK_TARGET_CPU_BITS" = "x32"; then C_O_FLAG_HIGHEST="$C_O_FLAG_HIGHEST -xchip=pentium" CXX_O_FLAG_HIGHEST="$CXX_O_FLAG_HIGHEST -xchip=pentium" fi elif test "x$OPENJDK_TARGET_CPU_ARCH" = "xsparc"; then + C_O_FLAG_HIGHEST_JVM="-xO4" C_O_FLAG_HIGHEST="-xO4 -Wc,-Qrm-s -Wc,-Qiselect-T0 $CC_HIGHEST -xalias_level=basic -xprefetch=auto,explicit -xchip=ultra" C_O_FLAG_HI="-xO4 -Wc,-Qrm-s -Wc,-Qiselect-T0" C_O_FLAG_NORM="-xO2 -Wc,-Qrm-s -Wc,-Qiselect-T0" C_O_FLAG_DEBUG="" + C_O_FLAG_DEBUG_JVM="" C_O_FLAG_NONE="" + CXX_O_FLAG_HIGHEST_JVM="-xO4" CXX_O_FLAG_HIGHEST="-xO4 -Qoption cg -Qrm-s -Qoption cg -Qiselect-T0 $CC_HIGHEST -xprefetch=auto,explicit -xchip=ultra" CXX_O_FLAG_HI="-xO4 -Qoption cg -Qrm-s -Qoption cg -Qiselect-T0" CXX_O_FLAG_NORM="-xO2 -Qoption cg -Qrm-s -Qoption cg -Qiselect-T0" CXX_O_FLAG_DEBUG="" + CXX_O_FLAG_DEBUG_JVM="" CXX_O_FLAG_NONE="" fi else @@ -48368,48 +48778,75 @@ $as_echo "$supports" >&6; } if test "x$OPENJDK_TARGET_OS" = xmacosx; then # On MacOSX we optimize for size, something # we should do for all platforms? + C_O_FLAG_HIGHEST_JVM="-Os" C_O_FLAG_HIGHEST="-Os" C_O_FLAG_HI="-Os" C_O_FLAG_NORM="-Os" + C_O_FLAG_SIZE="-Os" else + C_O_FLAG_HIGHEST_JVM="-O3" C_O_FLAG_HIGHEST="-O3" C_O_FLAG_HI="-O3" C_O_FLAG_NORM="-O2" + C_O_FLAG_SIZE="-Os" fi C_O_FLAG_DEBUG="-O0" + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + C_O_FLAG_DEBUG_JVM="" + elif test "x$OPENJDK_TARGET_OS" = xlinux; then + C_O_FLAG_DEBUG_JVM="-O0" + fi C_O_FLAG_NONE="-O0" elif test "x$TOOLCHAIN_TYPE" = xclang; then if test "x$OPENJDK_TARGET_OS" = xmacosx; then # On MacOSX we optimize for size, something # we should do for all platforms? + C_O_FLAG_HIGHEST_JVM="-Os" C_O_FLAG_HIGHEST="-Os" C_O_FLAG_HI="-Os" C_O_FLAG_NORM="-Os" + C_O_FLAG_SIZE="-Os" else + C_O_FLAG_HIGHEST_JVM="-O3" C_O_FLAG_HIGHEST="-O3" C_O_FLAG_HI="-O3" C_O_FLAG_NORM="-O2" + C_O_FLAG_SIZE="-Os" fi C_O_FLAG_DEBUG="-O0" + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + C_O_FLAG_DEBUG_JVM="" + elif test "x$OPENJDK_TARGET_OS" = xlinux; then + C_O_FLAG_DEBUG_JVM="-O0" + fi C_O_FLAG_NONE="-O0" elif test "x$TOOLCHAIN_TYPE" = xxlc; then + C_O_FLAG_HIGHEST_JVM="-O3" C_O_FLAG_HIGHEST="-O3" C_O_FLAG_HI="-O3 -qstrict" C_O_FLAG_NORM="-O2" C_O_FLAG_DEBUG="-qnoopt" + # FIXME: Value below not verified. + C_O_FLAG_DEBUG_JVM="" C_O_FLAG_NONE="-qnoopt" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + C_O_FLAG_HIGHEST_JVM="-O2 -Oy-" C_O_FLAG_HIGHEST="-O2" C_O_FLAG_HI="-O1" C_O_FLAG_NORM="-O1" C_O_FLAG_DEBUG="-Od" + C_O_FLAG_DEBUG_JVM="" C_O_FLAG_NONE="-Od" + C_O_FLAG_SIZE="-Os" fi + CXX_O_FLAG_HIGHEST_JVM="$C_O_FLAG_HIGHEST_JVM" CXX_O_FLAG_HIGHEST="$C_O_FLAG_HIGHEST" CXX_O_FLAG_HI="$C_O_FLAG_HI" CXX_O_FLAG_NORM="$C_O_FLAG_NORM" CXX_O_FLAG_DEBUG="$C_O_FLAG_DEBUG" + CXX_O_FLAG_DEBUG_JVM="$C_O_FLAG_DEBUG_JVM" CXX_O_FLAG_NONE="$C_O_FLAG_NONE" + CXX_O_FLAG_SIZE="$C_O_FLAG_SIZE" fi # Adjust optimization flags according to debug level. @@ -48424,12 +48861,16 @@ $as_echo "$supports" >&6; } ;; slowdebug ) # Disable optimization + C_O_FLAG_HIGHEST_JVM="$C_O_FLAG_DEBUG_JVM" C_O_FLAG_HIGHEST="$C_O_FLAG_DEBUG" C_O_FLAG_HI="$C_O_FLAG_DEBUG" C_O_FLAG_NORM="$C_O_FLAG_DEBUG" + C_O_FLAG_SIZE="$C_O_FLAG_DEBUG" + CXX_O_FLAG_HIGHEST_JVM="$CXX_O_FLAG_DEBUG_JVM" CXX_O_FLAG_HIGHEST="$CXX_O_FLAG_DEBUG" CXX_O_FLAG_HI="$CXX_O_FLAG_DEBUG" CXX_O_FLAG_NORM="$CXX_O_FLAG_DEBUG" + CXX_O_FLAG_SIZE="$CXX_O_FLAG_DEBUG" ;; esac @@ -48445,6 +48886,12 @@ $as_echo "$supports" >&6; } + + + + + + # Special extras... if test "x$TOOLCHAIN_TYPE" = xsolstudio; then if test "x$OPENJDK_TARGET_CPU_ARCH" = "xsparc"; then @@ -48556,10 +49003,23 @@ $as_echo "$supports" >&6; } CXXFLAGS_JDK="${CXXFLAGS_JDK} ${CXXSTD_CXXFLAG}" fi + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + CFLAGS_JDK="${CFLAGS_JDK} -D__solaris__" + CXXFLAGS_JDK="${CXXFLAGS_JDK} -D__solaris__" + CFLAGS_JDKLIB_EXTRA='-xstrconst' + CFLAGS_JDK="${CFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + CXXFLAGS_JDK="${CXXFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + fi - CFLAGS_JDK="${CFLAGS_JDK} $EXTRA_CFLAGS" - CXXFLAGS_JDK="${CXXFLAGS_JDK} $EXTRA_CXXFLAGS" - LDFLAGS_JDK="${LDFLAGS_JDK} $EXTRA_LDFLAGS" + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + CFLAGS_JDK="${CFLAGS_JDK} -D__solaris__" + CXXFLAGS_JDK="${CXXFLAGS_JDK} -D__solaris__" + CFLAGS_JDKLIB_EXTRA='-xstrconst' + fi + + CFLAGS_JDK="${CFLAGS_JDK} ${EXTRA_CFLAGS}" + CXXFLAGS_JDK="${CXXFLAGS_JDK} ${EXTRA_CXXFLAGS}" + LDFLAGS_JDK="${LDFLAGS_JDK} ${EXTRA_LDFLAGS}" ############################################################################### # @@ -48572,9 +49032,13 @@ $as_echo "$supports" >&6; } # CXXFLAGS_JDK - C++ Compiler flags # COMMON_CCXXFLAGS_JDK - common to C and C++ if test "x$TOOLCHAIN_TYPE" = xgcc; then + JVM_CFLAGS="$JVM_CFLAGS -D_GNU_SOURCE" + JVM_CFLAGS="$JVM_CFLAGS -D_REENTRANT" + JVM_CFLAGS="$JVM_CFLAGS -fcheck-new" if test "x$OPENJDK_TARGET_CPU" = xx86; then # Force compatibility with i586 on 32 bit intel platforms. COMMON_CCXXFLAGS="${COMMON_CCXXFLAGS} -march=i586" + JVM_CFLAGS="$JVM_CFLAGS -march=i586" fi COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" @@ -49211,11 +49675,19 @@ $as_echo "$supports" >&6; } elif test "x$TOOLCHAIN_TYPE" = xclang; then + JVM_CFLAGS="$JVM_CFLAGS -D_GNU_SOURCE" + + # Restrict the debug information created by Clang to avoid + # too big object files and speed the build up a little bit + # (see http://llvm.org/bugs/show_bug.cgi?id=7554) + JVM_CFLAGS="$JVM_CFLAGS -flimit-debug-info" if test "x$OPENJDK_TARGET_OS" = xlinux; then if test "x$OPENJDK_TARGET_CPU" = xx86; then # Force compatibility with i586 on 32 bit intel platforms. COMMON_CCXXFLAGS="${COMMON_CCXXFLAGS} -march=i586" + JVM_CFLAGS="$JVM_CFLAGS -march=i586" fi + JVM_CFLAGS="$JVM_CFLAGS -Wno-sometimes-uninitialized" COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" case $OPENJDK_TARGET_CPU_ARCH in @@ -49230,6 +49702,7 @@ $as_echo "$supports" >&6; } esac fi elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then + JVM_CFLAGS="$JVM_CFLAGS -DSPARC_WORKS" COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -DTRACING -DMACRO_MEMSYS_OPS -DBREAKPTS" if test "x$OPENJDK_TARGET_CPU_ARCH" = xx86; then COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DcpuIntel -Di586 -D$OPENJDK_TARGET_CPU_LEGACY_LIB" @@ -49238,6 +49711,7 @@ $as_echo "$supports" >&6; } CFLAGS_JDK="$CFLAGS_JDK -xc99=%none -xCC -errshort=tags -Xa -v -mt -W0,-noglobal" CXXFLAGS_JDK="$CXXFLAGS_JDK -errtags=yes +w -mt -features=no%except -DCC_NOEX -norunpath -xnolib" elif test "x$TOOLCHAIN_TYPE" = xxlc; then + JVM_CFLAGS="$JVM_CFLAGS -D_REENTRANT -D__STDC_FORMAT_MACROS" CFLAGS_JDK="$CFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" CXXFLAGS_JDK="$CXXFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then @@ -49258,6 +49732,7 @@ $as_echo "$supports" >&6; } if test "x$TOOLCHAIN_VERSION" = "x2010"; then STATIC_CPPLIB_FLAGS="-D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB" COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK $STATIC_CPPLIB_FLAGS" + JVM_CFLAGS="$JVM_CFLAGS $STATIC_CPPLIB_FLAGS" fi fi @@ -49307,12 +49782,9 @@ $as_echo "$supports" >&6; } COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D$OPENJDK_TARGET_OS_UPPERCASE" # Setup target CPU - OPENJDK_TARGET_CCXXFLAGS_JDK="$OPENJDK_TARGET_CCXXFLAGS_JDK \ - $ADD_LP64 \ + COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK \ + $OPENJDK_TARGET_ADD_LP64 \ -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY" - OPENJDK_BUILD_CCXXFLAGS_JDK="$OPENJDK_BUILD_CCXXFLAGS_JDK \ - $OPENJDK_BUILD_ADD_LP64 \ - -DARCH='\"$OPENJDK_BUILD_CPU_LEGACY\"' -D$OPENJDK_BUILD_CPU_LEGACY" # Setup debug/release defines if test "x$DEBUG_LEVEL" = xrelease; then @@ -49325,10 +49797,171 @@ $as_echo "$supports" >&6; } fi # Set some additional per-OS defines. - if test "x$OPENJDK_TARGET_OS" = xmacosx; then + if test "x$OPENJDK_TARGET_OS" = xlinux; then + JVM_CFLAGS="$JVM_CFLAGS -DLINUX" + JVM_CFLAGS="$JVM_CFLAGS -pipe -fPIC -fno-rtti -fno-exceptions \ + -fvisibility=hidden -fno-strict-aliasing -fno-omit-frame-pointer" + elif test "x$OPENJDK_TARGET_OS" = xsolaris; then + JVM_CFLAGS="$JVM_CFLAGS -DSOLARIS" + JVM_CFLAGS="$JVM_CFLAGS -template=no%extdef -features=no%split_init \ + -D_Crun_inline_placement -library=%none -KPIC -mt -xwe -features=no%except" + elif test "x$OPENJDK_TARGET_OS" = xmacosx; then COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" + JVM_CFLAGS="$JVM_CFLAGS -D_ALLBSD_SOURCE" + JVM_CFLAGS="$JVM_CFLAGS -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE" + JVM_CFLAGS="$JVM_CFLAGS -fno-rtti -fno-exceptions -fvisibility=hidden \ + -mno-omit-leaf-frame-pointer -mstack-alignment=16 -pipe -fno-strict-aliasing \ + -DMAC_OS_X_VERSION_MAX_ALLOWED=1070 -mmacosx-version-min=10.7.0 \ + -fno-omit-frame-pointer" + elif test "x$OPENJDK_TARGET_OS" = xaix; then + JVM_CFLAGS="$JVM_CFLAGS -DAIX" + # We may need '-qminimaltoc' or '-qpic=large -bbigtoc' if the TOC overflows. + JVM_CFLAGS="$JVM_CFLAGS -qtune=balanced -qhot=level=1 -qinline \ + -qinlglue -qalias=noansi -qstrict -qtls=default -qlanglvl=c99vla \ + -qlanglvl=noredefmac -qnortti -qnoeh -qignerrno" elif test "x$OPENJDK_TARGET_OS" = xbsd; then COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE" + elif test "x$OPENJDK_TARGET_OS" = xwindows; then + JVM_CFLAGS="$JVM_CFLAGS -D_WINDOWS -DWIN32 -D_JNI_IMPLEMENTATION_" + JVM_CFLAGS="$JVM_CFLAGS -nologo -W3 -MD -MP" + fi + + # Set some additional per-CPU defines. + if test "x$OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU" = xwindows-x86; then + JVM_CFLAGS="$JVM_CFLAGS -arch:IA32" + elif test "x$OPENJDK_TARGET_CPU" = xsparcv9; then + JVM_CFLAGS="$JVM_CFLAGS -xarch=sparc" + elif test "x$OPENJDK_TARGET_CPU" = xppc64; then + if test "x$OPENJDK_TARGET_OS" = xlinux; then + JVM_CFLAGS="$JVM_CFLAGS -minsert-sched-nops=regroup_exact -mno-multiple -mno-string" + if test "x$OPENJDK_TARGET_CPU_ENDIAN" = xbig; then + # fixes `relocation truncated to fit' error for gcc 4.1. + JVM_CFLAGS="$JVM_CFLAGS -mminimal-toc" + # Use ppc64 instructions, but schedule for power5 + JVM_CFLAGS="$JVM_CFLAGS -mcpu=powerpc64 -mtune=power5" + else + # Little endian machine uses ELFv2 ABI. + JVM_CFLAGS="$JVM_CFLAGS -DABI_ELFv2" + # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. + JVM_CFLAGS="$JVM_CFLAGS -mcpu=power7 -mtune=power8" + fi + elif test "x$OPENJDK_TARGET_OS" = xaix; then + JVM_CFLAGS="$JVM_CFLAGS -qarch=ppc64" + fi + fi + + if test "x$OPENJDK_TARGET_CPU_ENDIAN" = xlittle; then + JVM_CFLAGS="$JVM_CFLAGS -DVM_LITTLE_ENDIAN" + fi + + if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + if test "x$OPENJDK_TARGET_OS" != xsolaris && test "x$OPENJDK_TARGET_OS" != xaix; then + # Solaris does not have _LP64=1 in the old build. + # xlc on AIX defines _LP64=1 by default and issues a warning if we redefine it. + JVM_CFLAGS="$JVM_CFLAGS -D_LP64=1" + fi + fi + + # Set JVM_CFLAGS warning handling + if test "x$OPENJDK_TARGET_OS" = xlinux; then + JVM_CFLAGS="$JVM_CFLAGS -Wpointer-arith -Wsign-compare -Wunused-function \ + -Wunused-value -Woverloaded-virtual" + + if test "x$TOOLCHAIN_TYPE" = xgcc; then + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + + # Need to assign to a variable since m4 is blocked from modifying parts in []. + REFERENCE_VERSION=4.8 + + if [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 4.8, only three parts (X.Y.Z) is supported" "$LINENO" 5 + fi + + if [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 4.8, only parts < 99999 is supported" "$LINENO" 5 + fi + + # Version comparison method inspired by http://stackoverflow.com/a/24067243 + COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"` + + if test $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then + : + + # These flags either do not work or give spurious warnings prior to gcc 4.8. + JVM_CFLAGS="$JVM_CFLAGS -Wno-format-zero-length -Wtype-limits -Wuninitialized" + + + else + : + + fi + + + + + + + + + + + + + fi + if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then + # Non-zero builds have stricter warnings + JVM_CFLAGS="$JVM_CFLAGS -Wreturn-type -Wundef -Wformat=2" + else + if test "x$TOOLCHAIN_TYPE" = xclang; then + # Some versions of llvm do not like -Wundef + JVM_CFLAGS="$JVM_CFLAGS -Wno-undef" + fi + fi + elif test "x$OPENJDK_TARGET_OS" = xmacosx; then + JVM_CFLAGS="$JVM_CFLAGS -Wno-deprecated -Wpointer-arith \ + -Wsign-compare -Wundef -Wunused-function -Wformat=2" fi # Additional macosx handling @@ -49356,43 +49989,14 @@ $as_echo "$supports" >&6; } -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/libjava" # The shared libraries are compiled using the picflag. - CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK \ $CFLAGS_JDK $EXTRA_CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" - CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK \ $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" # Executable flags - CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ - $CFLAGS_JDK $EXTRA_CFLAGS_JDK" - CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ - $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK" - - # The corresponding flags for building for the build platform. This is still an - # approximation, we only need something that runs on this machine when cross - # compiling the product. - OPENJDK_BUILD_CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \ - $PICFLAG $CFLAGS_JDKLIB_EXTRA" - OPENJDK_BUILD_CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \ - $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" - OPENJDK_BUILD_CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK" - OPENJDK_BUILD_CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK" - - - - - - - - - - - # Flags for compiling test libraries - CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" - CXXFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" - - # Flags for compiling test executables - CFLAGS_TESTEXE="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK" - CXXFLAGS_TESTEXE="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK" + CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $EXTRA_CFLAGS_JDK" + CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK" @@ -49405,9 +50009,21 @@ $as_echo "$supports" >&6; } if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then LDFLAGS_MICROSOFT="-nologo -opt:ref" LDFLAGS_JDK="$LDFLAGS_JDK $LDFLAGS_MICROSOFT -incremental:no" + JVM_LDFLAGS="$JVM_LDFLAGS $LDFLAGS_MICROSOFT -opt:icf,8 -subsystem:windows -base:0x8000000" if test "x$OPENJDK_TARGET_CPU_BITS" = "x32"; then LDFLAGS_SAFESH="-safeseh" LDFLAGS_JDK="$LDFLAGS_JDK $LDFLAGS_SAFESH" + JVM_LDFLAGS="$JVM_LDFLAGS $LDFLAGS_SAFESH" + # NOTE: Old build added -machine. Probably not needed. + JVM_LDFLAGS="$JVM_LDFLAGS -machine:I386" + else + JVM_LDFLAGS="$JVM_LDFLAGS -machine:AMD64" + fi + elif test "x$TOOLCHAIN_TYPE" = xclang; then + JVM_LDFLAGS="$JVM_LDFLAGS -mno-omit-leaf-frame-pointer -mstack-alignment=16 -stdlib=libstdc++ -fPIC" + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + # FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead. + JVM_LDFLAGS="$JVM_LDFLAGS -Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." fi elif test "x$TOOLCHAIN_TYPE" = xgcc; then # If this is a --hash-style=gnu system, use --hash-style=both, why? @@ -49415,36 +50031,57 @@ $as_echo "$supports" >&6; } if test -n "$HAS_GNU_HASH"; then LDFLAGS_HASH_STYLE="-Wl,--hash-style=both" LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_HASH_STYLE" + JVM_LDFLAGS="$JVM_LDFLAGS $LDFLAGS_HASH_STYLE" + fi + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + JVM_LDFLAGS="$JVM_LDFLAGS -Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." fi if test "x$OPENJDK_TARGET_OS" = xlinux; then # And since we now know that the linker is gnu, then add -z defs, to forbid # undefined symbols in object files. LDFLAGS_NO_UNDEF_SYM="-Wl,-z,defs" LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_NO_UNDEF_SYM" + JVM_LDFLAGS="$JVM_LDFLAGS $LDFLAGS_NO_UNDEF_SYM" + LDFLAGS_NO_EXEC_STACK="-Wl,-z,noexecstack" + JVM_LDFLAGS="$JVM_LDFLAGS $LDFLAGS_NO_EXEC_STACK" + if test "x$OPENJDK_TARGET_CPU" = xx86; then + JVM_LDFLAGS="$JVM_LDFLAGS -march=i586" + fi case $DEBUG_LEVEL in release ) # tell linker to optimize libraries. # Should this be supplied to the OSS linker as well? LDFLAGS_DEBUGLEVEL_release="-Wl,-O1" LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_DEBUGLEVEL_release" + JVM_LDFLAGS="$JVM_LDFLAGS $LDFLAGS_DEBUGLEVEL_release" + if test "x$HAS_LINKER_RELRO" = "xtrue"; then + JVM_LDFLAGS="$JVM_LDFLAGS $LINKER_RELRO_FLAG" + fi ;; slowdebug ) + # Hotspot always let the linker optimize + JVM_LDFLAGS="$JVM_LDFLAGS -Wl,-O1" if test "x$HAS_LINKER_NOW" = "xtrue"; then # do relocations at load LDFLAGS_JDK="$LDFLAGS_JDK $LINKER_NOW_FLAG" LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LINKER_NOW_FLAG" + JVM_LDFLAGS="$JVM_LDFLAGS $LINKER_NOW_FLAG" fi if test "x$HAS_LINKER_RELRO" = "xtrue"; then # mark relocations read only LDFLAGS_JDK="$LDFLAGS_JDK $LINKER_RELRO_FLAG" LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LINKER_RELRO_FLAG" + JVM_LDFLAGS="$JVM_LDFLAGS $LINKER_RELRO_FLAG" fi ;; fastdebug ) + # Hotspot always let the linker optimize + JVM_LDFLAGS="$JVM_LDFLAGS -Wl,-O1" if test "x$HAS_LINKER_RELRO" = "xtrue"; then # mark relocations read only LDFLAGS_JDK="$LDFLAGS_JDK $LINKER_RELRO_FLAG" LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LINKER_RELRO_FLAG" + JVM_LDFLAGS="$JVM_LDFLAGS $LINKER_RELRO_FLAG" fi ;; * ) @@ -49457,9 +50094,14 @@ $as_echo "$supports" >&6; } LDFLAGS_JDK="$LDFLAGS_JDK $LDFLAGS_SOLSTUDIO -xildoff -ztext" LDFLAGS_CXX_SOLSTUDIO="-norunpath" LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LDFLAGS_CXX_SOLSTUDIO -xnolib" + JVM_LDFLAGS="$JVM_LDFLAGS $LDFLAGS_SOLSTUDIO -library=%none -mt $LDFLAGS_CXX_SOLSTUDIO -z noversion" + if test "x$OPENJDK_TARGET_CPU_ARCH" = "xsparc"; then + JVM_LDFLAGS="$JVM_LDFLAGS -xarch=sparc" + fi elif test "x$TOOLCHAIN_TYPE" = xxlc; then LDFLAGS_XLC="-b64 -brtl -bnolibpath -bexpall -bernotok" LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_XLC" + JVM_LDFLAGS="$JVM_LDFLAGS $LDFLAGS_XLC" fi # Customize LDFLAGS for executables @@ -49477,7 +50119,6 @@ $as_echo "$supports" >&6; } LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined" fi - OPENJDK_BUILD_LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE}" LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE} ${EXTRA_LDFLAGS_JDK}" # Customize LDFLAGS for libs @@ -49492,18 +50133,24 @@ $as_echo "$supports" >&6; } LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \ -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)" + if test "xTARGET" = "xTARGET"; then # On some platforms (mac) the linker warns about non existing -L dirs. # Add server first if available. Linking aginst client does not always produce the same results. - # Only add client dir if client is being built. Add minimal (note not minimal1) if only building minimal1. + # Only add client/minimal dir if client/minimal is being built. # Default to server for other variants. - if test "x$JVM_VARIANT_SERVER" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" - elif test "x$JVM_VARIANT_CLIENT" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/client" - elif test "x$JVM_VARIANT_MINIMAL1" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/minimal" + if [[ " $JVM_VARIANTS " =~ " server " ]] ; then + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" + elif [[ " $JVM_VARIANTS " =~ " client " ]] ; then + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/client" + elif [[ " $JVM_VARIANTS " =~ " minimal " ]] ; then + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/minimal" else - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" + fi + elif test "xTARGET" = "xBUILD"; then + # When building a buildjdk, it's always only the server variant + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \ + -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" fi JDKLIB_LIBS="-ljava -ljvm" @@ -49511,12 +50158,41 @@ $as_echo "$supports" >&6; } JDKLIB_LIBS="$JDKLIB_LIBS -lc" fi - # When building a buildjdk, it's always only the server variant - OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} \ - -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" fi - OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_JDKLIB}" + # Set JVM_LIBS (per os) + if test "x$OPENJDK_TARGET_OS" = xlinux; then + JVM_LIBS="$JVM_LIBS -lm -ldl -lpthread" + elif test "x$OPENJDK_TARGET_OS" = xsolaris; then + # FIXME: This hard-coded path is not really proper. + if test "x$OPENJDK_TARGET_CPU" = xx86_64; then + SOLARIS_LIBM_LIBS="/usr/lib/amd64/libm.so.1" + elif test "x$OPENJDK_TARGET_CPU" = xsparcv9; then + SOLARIS_LIBM_LIBS="/usr/lib/sparcv9/libm.so.1" + fi + JVM_LIBS="$JVM_LIBS -lsocket -lsched -ldl $SOLARIS_LIBM_LIBS -lCrun \ + -lthread -ldoor -lc -ldemangle -lnsl -lkstat -lrt" + elif test "x$OPENJDK_TARGET_OS" = xmacosx; then + JVM_LIBS="$JVM_LIBS -lm" + elif test "x$OPENJDK_TARGET_OS" = xaix; then + JVM_LIBS="$JVM_LIBS -Wl,-lC_r -lm -ldl -lpthread" + elif test "x$OPENJDK_TARGET_OS" = xbsd; then + JVM_LIBS="$JVM_LIBS -lm" + elif test "x$OPENJDK_TARGET_OS" = xwindows; then + JVM_LIBS="$JVM_LIBS kernel32.lib user32.lib gdi32.lib winspool.lib \ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib \ + wsock32.lib winmm.lib version.lib psapi.lib" + fi + + # Set JVM_ASFLAGS + if test "x$OPENJDK_TARGET_OS" = xlinux; then + if test "x$OPENJDK_TARGET_CPU" = xx86; then + JVM_ASFLAGS="$JVM_ASFLAGS -march=i586" + fi + elif test "x$OPENJDK_TARGET_OS" = xmacosx; then + JVM_ASFLAGS="$JVM_ASFLAGS -x assembler-with-cpp -mno-omit-leaf-frame-pointer -mstack-alignment=16" + fi + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${EXTRA_LDFLAGS_JDK}" @@ -49528,6 +50204,801 @@ $as_echo "$supports" >&6; } + + + + + + # Special extras... + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + if test "x$OPENJDK_BUILD_CPU_ARCH" = "xsparc"; then + OPENJDK_BUILD_CFLAGS_JDKLIB_EXTRA="${OPENJDK_BUILD_CFLAGS_JDKLIB_EXTRA} -xregs=no%appl" + OPENJDK_BUILD_CXXFLAGS_JDKLIB_EXTRA="${OPENJDK_BUILD_CXXFLAGS_JDKLIB_EXTRA} -xregs=no%appl" + fi + OPENJDK_BUILD_CFLAGS_JDKLIB_EXTRA="${OPENJDK_BUILD_CFLAGS_JDKLIB_EXTRA} -errtags=yes -errfmt" + OPENJDK_BUILD_CXXFLAGS_JDKLIB_EXTRA="${OPENJDK_BUILD_CXXFLAGS_JDKLIB_EXTRA} -errtags=yes -errfmt" + elif test "x$TOOLCHAIN_TYPE" = xxlc; then + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + OPENJDK_BUILD_CXXFLAGS_JDK="${OPENJDK_BUILD_CXXFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + elif test "x$TOOLCHAIN_TYPE" = xgcc; then + OPENJDK_BUILD_CXXSTD_CXXFLAG="-std=gnu++98" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the C++ compiler supports \"$OPENJDK_BUILD_CXXSTD_CXXFLAG -Werror\"" >&5 +$as_echo_n "checking if the C++ compiler supports \"$OPENJDK_BUILD_CXXSTD_CXXFLAG -Werror\"... " >&6; } + supports=yes + + saved_cxxflags="$CXXFLAGS" + CXXFLAGS="$CXXFLAG $OPENJDK_BUILD_CXXSTD_CXXFLAG -Werror" + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int i; +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + supports=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + CXXFLAGS="$saved_cxxflags" + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 +$as_echo "$supports" >&6; } + if test "x$supports" = "xyes" ; then + : + + else + : + OPENJDK_BUILD_CXXSTD_CXXFLAG="" + fi + + + + + + + + + + + + + OPENJDK_BUILD_CXXFLAGS_JDK="${OPENJDK_BUILD_CXXFLAGS_JDK} ${OPENJDK_BUILD_CXXSTD_CXXFLAG}" + + fi + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -D__solaris__" + OPENJDK_BUILD_CXXFLAGS_JDK="${OPENJDK_BUILD_CXXFLAGS_JDK} -D__solaris__" + OPENJDK_BUILD_CFLAGS_JDKLIB_EXTRA='-xstrconst' + CFLAGS_JDK="${CFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + CXXFLAGS_JDK="${CXXFLAGS_JDK} -qchars=signed -qfullpath -qsaveopt" + fi + + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -D__solaris__" + OPENJDK_BUILD_CXXFLAGS_JDK="${OPENJDK_BUILD_CXXFLAGS_JDK} -D__solaris__" + OPENJDK_BUILD_CFLAGS_JDKLIB_EXTRA='-xstrconst' + fi + + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} ${OPENJDK_BUILD_EXTRA_CFLAGS}" + OPENJDK_BUILD_CXXFLAGS_JDK="${OPENJDK_BUILD_CXXFLAGS_JDK} ${OPENJDK_BUILD_EXTRA_CXXFLAGS}" + OPENJDK_BUILD_LDFLAGS_JDK="${OPENJDK_BUILD_LDFLAGS_JDK} ${OPENJDK_BUILD_EXTRA_LDFLAGS}" + + ############################################################################### + # + # Now setup the CFLAGS and LDFLAGS for the JDK build. + # Later we will also have CFLAGS and LDFLAGS for the hotspot subrepo build. + # + + # Setup compiler/platform specific flags into + # OPENJDK_BUILD_CFLAGS_JDK - C Compiler flags + # OPENJDK_BUILD_CXXFLAGS_JDK - C++ Compiler flags + # OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK - common to C and C++ + if test "x$TOOLCHAIN_TYPE" = xgcc; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_GNU_SOURCE" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_REENTRANT" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -fcheck-new" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + # Force compatibility with i586 on 32 bit intel platforms. + OPENJDK_BUILD_COMMON_CCXXFLAGS="${OPENJDK_BUILD_COMMON_CCXXFLAGS} -march=i586" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -march=i586" + fi + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS $OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ + -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" + case $OPENJDK_BUILD_CPU_ARCH in + arm ) + # on arm we don't prevent gcc to omit frame pointer but do prevent strict aliasing + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -fno-strict-aliasing" + ;; + ppc ) + # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -fno-strict-aliasing" + ;; + * ) + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer" + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -fno-strict-aliasing" + ;; + esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + + # Need to assign to a variable since m4 is blocked from modifying parts in []. + REFERENCE_VERSION=6 + + if [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 6, only three parts (X.Y.Z) is supported" "$LINENO" 5 + fi + + if [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 6, only parts < 99999 is supported" "$LINENO" 5 + fi + + # Version comparison method inspired by http://stackoverflow.com/a/24067243 + COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"` + + if test $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then + : + + else + : + + fi + + + + + + + + + + + + + elif test "x$TOOLCHAIN_TYPE" = xclang; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_GNU_SOURCE" + + # Restrict the debug information created by Clang to avoid + # too big object files and speed the build up a little bit + # (see http://llvm.org/bugs/show_bug.cgi?id=7554) + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -flimit-debug-info" + if test "x$OPENJDK_BUILD_OS" = xlinux; then + if test "x$OPENJDK_BUILD_CPU" = xx86; then + # Force compatibility with i586 on 32 bit intel platforms. + OPENJDK_BUILD_COMMON_CCXXFLAGS="${OPENJDK_BUILD_COMMON_CCXXFLAGS} -march=i586" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -march=i586" + fi + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -Wno-sometimes-uninitialized" + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS $OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ + -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" + case $OPENJDK_BUILD_CPU_ARCH in + ppc ) + # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -fno-strict-aliasing" + ;; + * ) + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer" + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -fno-strict-aliasing" + ;; + esac + fi + elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DSPARC_WORKS" + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS $OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -DTRACING -DMACRO_MEMSYS_OPS -DBREAKPTS" + if test "x$OPENJDK_BUILD_CPU_ARCH" = xx86; then + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -DcpuIntel -Di586 -D$OPENJDK_BUILD_CPU_LEGACY_LIB" + fi + + OPENJDK_BUILD_CFLAGS_JDK="$OPENJDK_BUILD_CFLAGS_JDK -xc99=%none -xCC -errshort=tags -Xa -v -mt -W0,-noglobal" + OPENJDK_BUILD_CXXFLAGS_JDK="$OPENJDK_BUILD_CXXFLAGS_JDK -errtags=yes +w -mt -features=no%except -DCC_NOEX -norunpath -xnolib" + elif test "x$TOOLCHAIN_TYPE" = xxlc; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_REENTRANT -D__STDC_FORMAT_MACROS" + OPENJDK_BUILD_CFLAGS_JDK="$OPENJDK_BUILD_CFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" + OPENJDK_BUILD_CXXFLAGS_JDK="$OPENJDK_BUILD_CXXFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS $OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK \ + -MD -Zc:wchar_t- -W3 -wd4800 \ + -DWIN32_LEAN_AND_MEAN \ + -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE \ + -D_WINSOCK_DEPRECATED_NO_WARNINGS \ + -DWIN32 -DIAL" + if test "x$OPENJDK_BUILD_CPU" = xx86_64; then + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D_AMD64_ -Damd64" + else + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D_X86_ -Dx86" + fi + # If building with Visual Studio 2010, we can still use _STATIC_CPPLIB to + # avoid bundling msvcpNNN.dll. Doesn't work with newer versions of visual + # studio. + if test "x$TOOLCHAIN_VERSION" = "x2010"; then + STATIC_CPPLIB_FLAGS="-D_STATIC_CPPLIB -D_DISABLE_DEPRECATE_STATIC_CPPLIB" + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK $STATIC_CPPLIB_FLAGS" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS $STATIC_CPPLIB_FLAGS" + fi + fi + + ############################################################################### + + # Adjust flags according to debug level. + case $DEBUG_LEVEL in + fastdebug | slowdebug ) + OPENJDK_BUILD_CFLAGS_JDK="$OPENJDK_BUILD_CFLAGS_JDK $CFLAGS_DEBUG_SYMBOLS $CFLAGS_DEBUG_OPTIONS" + OPENJDK_BUILD_CXXFLAGS_JDK="$OPENJDK_BUILD_CXXFLAGS_JDK $CXXFLAGS_DEBUG_SYMBOLS $CXXFLAGS_DEBUG_OPTIONS" + JAVAC_FLAGS="$JAVAC_FLAGS -g" + ;; + release ) + ;; + * ) + as_fn_error $? "Unrecognized \$DEBUG_LEVEL: $DEBUG_LEVEL" "$LINENO" 5 + ;; + esac + + # Set some common defines. These works for all compilers, but assume + # -D is universally accepted. + + # Setup endianness + if test "x$OPENJDK_BUILD_CPU_ENDIAN" = xlittle; then + # The macro _LITTLE_ENDIAN needs to be defined the same to avoid the + # Sun C compiler warning message: warning: macro redefined: _LITTLE_ENDIAN + # (The Solaris X86 system defines this in file /usr/include/sys/isa_defs.h). + # Note: -Dmacro is the same as #define macro 1 + # -Dmacro= is the same as #define macro + if test "x$OPENJDK_BUILD_OS" = xsolaris; then + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D_LITTLE_ENDIAN=" + else + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D_LITTLE_ENDIAN" + fi + else + # Same goes for _BIG_ENDIAN. Do we really need to set *ENDIAN on Solaris if they + # are defined in the system? + if test "x$OPENJDK_BUILD_OS" = xsolaris; then + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D_BIG_ENDIAN=" + else + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D_BIG_ENDIAN" + fi + fi + + # Setup target OS define. Use OS target name but in upper case. + OPENJDK_BUILD_OS_UPPERCASE=`$ECHO $OPENJDK_BUILD_OS | $TR 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D$OPENJDK_BUILD_OS_UPPERCASE" + + # Setup target CPU + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK \ + $OPENJDK_BUILD_ADD_LP64 \ + -DARCH='\"$OPENJDK_BUILD_CPU_LEGACY\"' -D$OPENJDK_BUILD_CPU_LEGACY" + + # Setup debug/release defines + if test "x$DEBUG_LEVEL" = xrelease; then + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -DNDEBUG" + if test "x$OPENJDK_BUILD_OS" = xsolaris; then + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -DTRIMMED" + fi + else + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -DDEBUG" + fi + + # Set some additional per-OS defines. + if test "x$OPENJDK_BUILD_OS" = xlinux; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DLINUX" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -pipe -fPIC -fno-rtti -fno-exceptions \ + -fvisibility=hidden -fno-strict-aliasing -fno-omit-frame-pointer" + elif test "x$OPENJDK_BUILD_OS" = xsolaris; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DSOLARIS" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -template=no%extdef -features=no%split_init \ + -D_Crun_inline_placement -library=%none -KPIC -mt -xwe -features=no%except" + elif test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_ALLBSD_SOURCE" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -fno-rtti -fno-exceptions -fvisibility=hidden \ + -mno-omit-leaf-frame-pointer -mstack-alignment=16 -pipe -fno-strict-aliasing \ + -DMAC_OS_X_VERSION_MAX_ALLOWED=1070 -mmacosx-version-min=10.7.0 \ + -fno-omit-frame-pointer" + elif test "x$OPENJDK_BUILD_OS" = xaix; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DAIX" + # We may need '-qminimaltoc' or '-qpic=large -bbigtoc' if the TOC overflows. + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -qtune=balanced -qhot=level=1 -qinline \ + -qinlglue -qalias=noansi -qstrict -qtls=default -qlanglvl=c99vla \ + -qlanglvl=noredefmac -qnortti -qnoeh -qignerrno" + elif test "x$OPENJDK_BUILD_OS" = xbsd; then + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE" + elif test "x$OPENJDK_BUILD_OS" = xwindows; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_WINDOWS -DWIN32 -D_JNI_IMPLEMENTATION_" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -nologo -W3 -MD -MP" + fi + + # Set some additional per-CPU defines. + if test "x$OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU" = xwindows-x86; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -arch:IA32" + elif test "x$OPENJDK_BUILD_CPU" = xsparcv9; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -xarch=sparc" + elif test "x$OPENJDK_BUILD_CPU" = xppc64; then + if test "x$OPENJDK_BUILD_OS" = xlinux; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -minsert-sched-nops=regroup_exact -mno-multiple -mno-string" + if test "x$OPENJDK_BUILD_CPU_ENDIAN" = xbig; then + # fixes `relocation truncated to fit' error for gcc 4.1. + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mminimal-toc" + # Use ppc64 instructions, but schedule for power5 + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mcpu=powerpc64 -mtune=power5" + else + # Little endian machine uses ELFv2 ABI. + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DABI_ELFv2" + # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mcpu=power7 -mtune=power8" + fi + elif test "x$OPENJDK_BUILD_OS" = xaix; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -qarch=ppc64" + fi + fi + + if test "x$OPENJDK_BUILD_CPU_ENDIAN" = xlittle; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DVM_LITTLE_ENDIAN" + fi + + if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then + if test "x$OPENJDK_BUILD_OS" != xsolaris && test "x$OPENJDK_BUILD_OS" != xaix; then + # Solaris does not have _LP64=1 in the old build. + # xlc on AIX defines _LP64=1 by default and issues a warning if we redefine it. + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_LP64=1" + fi + fi + + # Set OPENJDK_BUILD_JVM_CFLAGS warning handling + if test "x$OPENJDK_BUILD_OS" = xlinux; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -Wpointer-arith -Wsign-compare -Wunused-function \ + -Wunused-value -Woverloaded-virtual" + + if test "x$TOOLCHAIN_TYPE" = xgcc; then + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + + # Need to assign to a variable since m4 is blocked from modifying parts in []. + REFERENCE_VERSION=4.8 + + if [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 4.8, only three parts (X.Y.Z) is supported" "$LINENO" 5 + fi + + if [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 4.8, only parts < 99999 is supported" "$LINENO" 5 + fi + + # Version comparison method inspired by http://stackoverflow.com/a/24067243 + COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"` + + if test $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then + : + + # These flags either do not work or give spurious warnings prior to gcc 4.8. + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -Wno-format-zero-length -Wtype-limits -Wuninitialized" + + + else + : + + fi + + + + + + + + + + + + + fi + if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then + # Non-zero builds have stricter warnings + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -Wreturn-type -Wundef -Wformat=2" + else + if test "x$TOOLCHAIN_TYPE" = xclang; then + # Some versions of llvm do not like -Wundef + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -Wno-undef" + fi + fi + elif test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -Wno-deprecated -Wpointer-arith \ + -Wsign-compare -Wundef -Wunused-function -Wformat=2" + fi + + # Additional macosx handling + if test "x$OPENJDK_BUILD_OS" = xmacosx; then + # Setting these parameters makes it an error to link to macosx APIs that are + # newer than the given OS version and makes the linked binaries compatible + # even if built on a newer version of the OS. + # The expected format is X.Y.Z + MACOSX_VERSION_MIN=10.7.0 + + + # The macro takes the version with no dots, ex: 1070 + # Let the flags variables get resolved in make for easier override on make + # command line. + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -DMAC_OS_X_VERSION_MAX_ALLOWED=\$(subst .,,\$(MACOSX_VERSION_MIN)) -mmacosx-version-min=\$(MACOSX_VERSION_MIN)" + OPENJDK_BUILD_LDFLAGS_JDK="$OPENJDK_BUILD_LDFLAGS_JDK -mmacosx-version-min=\$(MACOSX_VERSION_MIN)" + fi + + # Setup some hard coded includes + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK \ + -I${JDK_TOPDIR}/src/java.base/share/native/include \ + -I${JDK_TOPDIR}/src/java.base/$OPENJDK_BUILD_OS/native/include \ + -I${JDK_TOPDIR}/src/java.base/$OPENJDK_BUILD_OS_TYPE/native/include \ + -I${JDK_TOPDIR}/src/java.base/share/native/libjava \ + -I${JDK_TOPDIR}/src/java.base/$OPENJDK_BUILD_OS_TYPE/native/libjava" + + # The shared libraries are compiled using the picflag. + OPENJDK_BUILD_CFLAGS_JDKLIB="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK \ + $OPENJDK_BUILD_CFLAGS_JDK $OPENJDK_BUILD_EXTRA_CFLAGS_JDK $PICFLAG $OPENJDK_BUILD_CFLAGS_JDKLIB_EXTRA" + OPENJDK_BUILD_CXXFLAGS_JDKLIB="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK \ + $OPENJDK_BUILD_CXXFLAGS_JDK $OPENJDK_BUILD_EXTRA_CXXFLAGS_JDK $PICFLAG $OPENJDK_BUILD_CXXFLAGS_JDKLIB_EXTRA" + + # Executable flags + OPENJDK_BUILD_CFLAGS_JDKEXE="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CFLAGS_JDK $OPENJDK_BUILD_EXTRA_CFLAGS_JDK" + OPENJDK_BUILD_CXXFLAGS_JDKEXE="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CXXFLAGS_JDK $OPENJDK_BUILD_EXTRA_CXXFLAGS_JDK" + + + + + + + # Setup LDFLAGS et al. + # + + if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + LDFLAGS_MICROSOFT="-nologo -opt:ref" + OPENJDK_BUILD_LDFLAGS_JDK="$OPENJDK_BUILD_LDFLAGS_JDK $LDFLAGS_MICROSOFT -incremental:no" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LDFLAGS_MICROSOFT -opt:icf,8 -subsystem:windows -base:0x8000000" + if test "x$OPENJDK_BUILD_CPU_BITS" = "x32"; then + LDFLAGS_SAFESH="-safeseh" + OPENJDK_BUILD_LDFLAGS_JDK="$OPENJDK_BUILD_LDFLAGS_JDK $LDFLAGS_SAFESH" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LDFLAGS_SAFESH" + # NOTE: Old build added -machine. Probably not needed. + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -machine:I386" + else + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -machine:AMD64" + fi + elif test "x$TOOLCHAIN_TYPE" = xclang; then + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -mno-omit-leaf-frame-pointer -mstack-alignment=16 -stdlib=libstdc++ -fPIC" + if test "x$OPENJDK_BUILD_OS" = xmacosx; then + # FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead. + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." + fi + elif test "x$TOOLCHAIN_TYPE" = xgcc; then + # If this is a --hash-style=gnu system, use --hash-style=both, why? + # We have previously set HAS_GNU_HASH if this is the case + if test -n "$HAS_GNU_HASH"; then + OPENJDK_BUILD_LDFLAGS_HASH_STYLE="-Wl,--hash-style=both" + OPENJDK_BUILD_LDFLAGS_JDK="${OPENJDK_BUILD_LDFLAGS_JDK} $OPENJDK_BUILD_LDFLAGS_HASH_STYLE" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $OPENJDK_BUILD_LDFLAGS_HASH_STYLE" + fi + if test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." + fi + if test "x$OPENJDK_BUILD_OS" = xlinux; then + # And since we now know that the linker is gnu, then add -z defs, to forbid + # undefined symbols in object files. + LDFLAGS_NO_UNDEF_SYM="-Wl,-z,defs" + OPENJDK_BUILD_LDFLAGS_JDK="${OPENJDK_BUILD_LDFLAGS_JDK} $LDFLAGS_NO_UNDEF_SYM" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LDFLAGS_NO_UNDEF_SYM" + LDFLAGS_NO_EXEC_STACK="-Wl,-z,noexecstack" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LDFLAGS_NO_EXEC_STACK" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -march=i586" + fi + case $DEBUG_LEVEL in + release ) + # tell linker to optimize libraries. + # Should this be supplied to the OSS linker as well? + LDFLAGS_DEBUGLEVEL_release="-Wl,-O1" + OPENJDK_BUILD_LDFLAGS_JDK="${OPENJDK_BUILD_LDFLAGS_JDK} $LDFLAGS_DEBUGLEVEL_release" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LDFLAGS_DEBUGLEVEL_release" + if test "x$HAS_LINKER_RELRO" = "xtrue"; then + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LINKER_RELRO_FLAG" + fi + ;; + slowdebug ) + # Hotspot always let the linker optimize + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -Wl,-O1" + if test "x$HAS_LINKER_NOW" = "xtrue"; then + # do relocations at load + OPENJDK_BUILD_LDFLAGS_JDK="$OPENJDK_BUILD_LDFLAGS_JDK $LINKER_NOW_FLAG" + OPENJDK_BUILD_LDFLAGS_CXX_JDK="$OPENJDK_BUILD_LDFLAGS_CXX_JDK $LINKER_NOW_FLAG" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LINKER_NOW_FLAG" + fi + if test "x$HAS_LINKER_RELRO" = "xtrue"; then + # mark relocations read only + OPENJDK_BUILD_LDFLAGS_JDK="$OPENJDK_BUILD_LDFLAGS_JDK $LINKER_RELRO_FLAG" + OPENJDK_BUILD_LDFLAGS_CXX_JDK="$OPENJDK_BUILD_LDFLAGS_CXX_JDK $LINKER_RELRO_FLAG" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LINKER_RELRO_FLAG" + fi + ;; + fastdebug ) + # Hotspot always let the linker optimize + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -Wl,-O1" + if test "x$HAS_LINKER_RELRO" = "xtrue"; then + # mark relocations read only + OPENJDK_BUILD_LDFLAGS_JDK="$OPENJDK_BUILD_LDFLAGS_JDK $LINKER_RELRO_FLAG" + OPENJDK_BUILD_LDFLAGS_CXX_JDK="$OPENJDK_BUILD_LDFLAGS_CXX_JDK $LINKER_RELRO_FLAG" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LINKER_RELRO_FLAG" + fi + ;; + * ) + as_fn_error $? "Unrecognized \$DEBUG_LEVEL: $DEBUG_LEVEL" "$LINENO" 5 + ;; + esac + fi + elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then + LDFLAGS_SOLSTUDIO="-Wl,-z,defs" + OPENJDK_BUILD_LDFLAGS_JDK="$OPENJDK_BUILD_LDFLAGS_JDK $LDFLAGS_SOLSTUDIO -xildoff -ztext" + LDFLAGS_CXX_SOLSTUDIO="-norunpath" + OPENJDK_BUILD_LDFLAGS_CXX_JDK="$OPENJDK_BUILD_LDFLAGS_CXX_JDK $LDFLAGS_CXX_SOLSTUDIO -xnolib" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LDFLAGS_SOLSTUDIO -library=%none -mt $LDFLAGS_CXX_SOLSTUDIO -z noversion" + if test "x$OPENJDK_BUILD_CPU_ARCH" = "xsparc"; then + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -xarch=sparc" + fi + elif test "x$TOOLCHAIN_TYPE" = xxlc; then + LDFLAGS_XLC="-b64 -brtl -bnolibpath -bexpall -bernotok" + OPENJDK_BUILD_LDFLAGS_JDK="${OPENJDK_BUILD_LDFLAGS_JDK} $LDFLAGS_XLC" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $LDFLAGS_XLC" + fi + + # Customize LDFLAGS for executables + + OPENJDK_BUILD_LDFLAGS_JDKEXE="${OPENJDK_BUILD_LDFLAGS_JDK}" + + if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + if test "x$OPENJDK_BUILD_CPU_BITS" = "x64"; then + LDFLAGS_STACK_SIZE=1048576 + else + LDFLAGS_STACK_SIZE=327680 + fi + OPENJDK_BUILD_LDFLAGS_JDKEXE="${OPENJDK_BUILD_LDFLAGS_JDKEXE} /STACK:$LDFLAGS_STACK_SIZE" + elif test "x$OPENJDK_BUILD_OS" = xlinux; then + OPENJDK_BUILD_LDFLAGS_JDKEXE="$OPENJDK_BUILD_LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined" + fi + + OPENJDK_BUILD_LDFLAGS_JDKEXE="${OPENJDK_BUILD_LDFLAGS_JDKEXE} ${OPENJDK_BUILD_EXTRA_LDFLAGS_JDK}" + + # Customize LDFLAGS for libs + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDK}" + + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}" + if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} \ + -libpath:${OUTPUT_ROOT}/support/modules_libs/java.base" + OPENJDK_BUILD_JDKLIB_LIBS="" + else + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} \ + -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)" + + if test "xBUILD" = "xTARGET"; then + # On some platforms (mac) the linker warns about non existing -L dirs. + # Add server first if available. Linking aginst client does not always produce the same results. + # Only add client/minimal dir if client/minimal is being built. + # Default to server for other variants. + if [[ " $JVM_VARIANTS " =~ " server " ]] ; then + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/server" + elif [[ " $JVM_VARIANTS " =~ " client " ]] ; then + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/client" + elif [[ " $JVM_VARIANTS " =~ " minimal " ]] ; then + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/minimal" + else + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/server" + fi + elif test "xBUILD" = "xBUILD"; then + # When building a buildjdk, it's always only the server variant + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} \ + -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/server" + fi + + OPENJDK_BUILD_JDKLIB_LIBS="-ljava -ljvm" + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + OPENJDK_BUILD_JDKLIB_LIBS="$OPENJDK_BUILD_JDKLIB_LIBS -lc" + fi + + fi + + # Set OPENJDK_BUILD_JVM_LIBS (per os) + if test "x$OPENJDK_BUILD_OS" = xlinux; then + OPENJDK_BUILD_JVM_LIBS="$OPENJDK_BUILD_JVM_LIBS -lm -ldl -lpthread" + elif test "x$OPENJDK_BUILD_OS" = xsolaris; then + # FIXME: This hard-coded path is not really proper. + if test "x$OPENJDK_BUILD_CPU" = xx86_64; then + OPENJDK_BUILD_SOLARIS_LIBM_LIBS="/usr/lib/amd64/libm.so.1" + elif test "x$OPENJDK_BUILD_CPU" = xsparcv9; then + OPENJDK_BUILD_SOLARIS_LIBM_LIBS="/usr/lib/sparcv9/libm.so.1" + fi + OPENJDK_BUILD_JVM_LIBS="$OPENJDK_BUILD_JVM_LIBS -lsocket -lsched -ldl $SOLARIS_LIBM_LIBS -lCrun \ + -lthread -ldoor -lc -ldemangle -lnsl -lkstat -lrt" + elif test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_JVM_LIBS="$OPENJDK_BUILD_JVM_LIBS -lm" + elif test "x$OPENJDK_BUILD_OS" = xaix; then + OPENJDK_BUILD_JVM_LIBS="$OPENJDK_BUILD_JVM_LIBS -Wl,-lC_r -lm -ldl -lpthread" + elif test "x$OPENJDK_BUILD_OS" = xbsd; then + OPENJDK_BUILD_JVM_LIBS="$OPENJDK_BUILD_JVM_LIBS -lm" + elif test "x$OPENJDK_BUILD_OS" = xwindows; then + OPENJDK_BUILD_JVM_LIBS="$OPENJDK_BUILD_JVM_LIBS kernel32.lib user32.lib gdi32.lib winspool.lib \ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib \ + wsock32.lib winmm.lib version.lib psapi.lib" + fi + + # Set OPENJDK_BUILD_JVM_ASFLAGS + if test "x$OPENJDK_BUILD_OS" = xlinux; then + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_JVM_ASFLAGS="$OPENJDK_BUILD_JVM_ASFLAGS -march=i586" + fi + elif test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_JVM_ASFLAGS="$OPENJDK_BUILD_JVM_ASFLAGS -x assembler-with-cpp -mno-omit-leaf-frame-pointer -mstack-alignment=16" + fi + + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${OPENJDK_BUILD_EXTRA_LDFLAGS_JDK}" + + + + + + + + + + + + + + + + # Tests are only ever compiled for TARGET + # Flags for compiling test libraries + CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" + CXXFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" + + # Flags for compiling test executables + CFLAGS_TESTEXE="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK" + CXXFLAGS_TESTEXE="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK" + + + + + + LDFLAGS_TESTLIB="$LDFLAGS_JDKLIB" LDFLAGS_TESTEXE="$LDFLAGS_JDKEXE" @@ -49535,6 +51006,7 @@ $as_echo "$supports" >&6; } + # Some Zero and Shark settings. # ZERO_ARCHFLAG tells the compiler which mode to build for case "${OPENJDK_TARGET_CPU}" in @@ -50883,6 +52355,222 @@ $as_echo "no" >&6; } +# Need toolchain to setup dtrace + + # Test for dtrace dependencies + # Check whether --enable-dtrace was given. +if test "${enable_dtrace+set}" = set; then : + enableval=$enable_dtrace; +fi + + + DTRACE_DEP_MISSING=false + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dtrace tool" >&5 +$as_echo_n "checking for dtrace tool... " >&6; } + if test "x$DTRACE" != "x" && test -x "$DTRACE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DTRACE" >&5 +$as_echo "$DTRACE" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found, cannot build dtrace" >&5 +$as_echo "not found, cannot build dtrace" >&6; } + DTRACE_DEP_MISSING=true + fi + + for ac_header in sys/sdt.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sys/sdt.h" "ac_cv_header_sys_sdt_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sdt_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_SDT_H 1 +_ACEOF + DTRACE_HEADERS_OK=yes +else + DTRACE_HEADERS_OK=no +fi + +done + + if test "x$DTRACE_HEADERS_OK" != "xyes"; then + DTRACE_DEP_MISSING=true + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if dtrace should be built" >&5 +$as_echo_n "checking if dtrace should be built... " >&6; } + if test "x$enable_dtrace" = "xyes"; then + if test "x$DTRACE_DEP_MISSING" = "xtrue"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, missing dependencies" >&5 +$as_echo "no, missing dependencies" >&6; } + + # Print a helpful message on how to acquire the necessary build dependency. + # dtrace is the help tag: freetype, cups, alsa etc + MISSING_DEPENDENCY=dtrace + + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + cygwin_help $MISSING_DEPENDENCY + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + msys_help $MISSING_DEPENDENCY + else + PKGHANDLER_COMMAND= + + case $PKGHANDLER in + apt-get) + apt_help $MISSING_DEPENDENCY ;; + yum) + yum_help $MISSING_DEPENDENCY ;; + port) + port_help $MISSING_DEPENDENCY ;; + pkgutil) + pkgutil_help $MISSING_DEPENDENCY ;; + pkgadd) + pkgadd_help $MISSING_DEPENDENCY ;; + esac + + if test "x$PKGHANDLER_COMMAND" != x; then + HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'." + fi + fi + + as_fn_error $? "Cannot enable dtrace with missing dependencies. See above. $HELP_MSG" "$LINENO" 5 + else + INCLUDE_DTRACE=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, forced" >&5 +$as_echo "yes, forced" >&6; } + fi + elif test "x$enable_dtrace" = "xno"; then + INCLUDE_DTRACE=false + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5 +$as_echo "no, forced" >&6; } + elif test "x$enable_dtrace" = "xauto" || test "x$enable_dtrace" = "x"; then + if test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK" != "xtrue"; then + INCLUDE_DTRACE=false + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, non-open linux build" >&5 +$as_echo "no, non-open linux build" >&6; } + elif test "x$DTRACE_DEP_MISSING" = "xtrue"; then + INCLUDE_DTRACE=false + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, missing dependencies" >&5 +$as_echo "no, missing dependencies" >&6; } + else + INCLUDE_DTRACE=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, dependencies present" >&5 +$as_echo "yes, dependencies present" >&6; } + fi + else + as_fn_error $? "Invalid value for --enable-dtrace: $enable_dtrace" "$LINENO" 5 + fi + + + + # The user can in some cases supply additional jvm features. For the custom + # variant, this defines the entire variant. + +# Check whether --with-jvm-features was given. +if test "${with_jvm_features+set}" = set; then : + withval=$with_jvm_features; +fi + + if test "x$with_jvm_features" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking additional JVM features" >&5 +$as_echo_n "checking additional JVM features... " >&6; } + JVM_FEATURES=`$ECHO $with_jvm_features | $SED -e 's/,/ /g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JVM_FEATURES" >&5 +$as_echo "$JVM_FEATURES" >&6; } + fi + + # Verify that dependencies are met for explicitly set features. + if [[ " $JVM_FEATURES " =~ " jvmti " ]] && ! [[ " $JVM_FEATURES " =~ " services " ]] ; then + as_fn_error $? "Specified JVM feature 'jvmti' requires feature 'services'" "$LINENO" 5 + fi + + if [[ " $JVM_FEATURES " =~ " management " ]] && ! [[ " $JVM_FEATURES " =~ " nmt " ]] ; then + as_fn_error $? "Specified JVM feature 'management' requires feature 'nmt'" "$LINENO" 5 + fi + + if [[ " $JVM_FEATURES " =~ " jvmci " ]] && ! [[ " $JVM_FEATURES " =~ " compiler2 " ]] ; then + as_fn_error $? "Specified JVM feature 'jvmci' requires feature 'compiler2'" "$LINENO" 5 + fi + + if [[ " $JVM_FEATURES " =~ " compiler2 " ]] && ! [[ " $JVM_FEATURES " =~ " all-gcs " ]] ; then + as_fn_error $? "Specified JVM feature 'compiler2' requires feature 'all-gcs'" "$LINENO" 5 + fi + + if [[ " $JVM_FEATURES " =~ " vm-structs " ]] && ! [[ " $JVM_FEATURES " =~ " all-gcs " ]] ; then + as_fn_error $? "Specified JVM feature 'vm-structs' requires feature 'all-gcs'" "$LINENO" 5 + fi + + # Turn on additional features based on other parts of configure + if test "x$INCLUDE_DTRACE" = "xtrue"; then + JVM_FEATURES="$JVM_FEATURES dtrace" + else + if [[ " $JVM_FEATURES " =~ " dtrace " ]] ; then + as_fn_error $? "To enable dtrace, you must use --enable-dtrace" "$LINENO" 5 + fi + fi + + if test "x$STATIC_BUILD" = "xtrue"; then + JVM_FEATURES="$JVM_FEATURES static-build" + else + if [[ " $JVM_FEATURES " =~ " static-build " ]] ; then + as_fn_error $? "To enable static-build, you must use --enable-static-build" "$LINENO" 5 + fi + fi + + if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then + if [[ " $JVM_FEATURES " =~ " zero " ]] ; then + as_fn_error $? "To enable zero/zeroshark, you must use --with-jvm-variants=zero/zeroshark" "$LINENO" 5 + fi + fi + + if ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then + if [[ " $JVM_FEATURES " =~ " shark " ]] ; then + as_fn_error $? "To enable shark, you must use --with-jvm-variants=zeroshark" "$LINENO" 5 + fi + fi + + # Only enable jvmci on x86_64, sparcv9 and aarch64, and only on server. + if test "x$OPENJDK_TARGET_CPU" = "xx86_64" || \ + test "x$OPENJDK_TARGET_CPU" = "xsparcv9" || \ + test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then + JVM_FEATURES_jvmci="jvmci" + else + JVM_FEATURES_jvmci="" + fi + + # All variants but minimal (and custom) get these features + NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti fprof vm-structs jni-check services management all-gcs nmt cds" + + # Enable features depending on variant. + JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci" + JVM_FEATURES_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES" + JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES" + JVM_FEATURES_minimal="compiler1 minimal $JVM_FEATURES" + JVM_FEATURES_zero="zero $NON_MINIMAL_FEATURES $JVM_FEATURES" + JVM_FEATURES_zeroshark="zero shark $NON_MINIMAL_FEATURES $JVM_FEATURES" + JVM_FEATURES_custom="$JVM_FEATURES" + + + + + + + + + + # Used for verification of Makefiles by check-jvm-feature + + + # We don't support --with-jvm-interpreter anymore, use zero instead. + + +# Check whether --with-jvm-interpreter was given. +if test "${with_jvm_interpreter+set}" = set; then : + withval=$with_jvm_interpreter; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-jvm-interpreter is deprecated and will be ignored." >&5 +$as_echo "$as_me: WARNING: Option --with-jvm-interpreter is deprecated and will be ignored." >&2;} +fi + + + + ############################################################################### # # Check dependencies for external and internal libraries. @@ -51009,7 +52697,7 @@ $as_echo "yes" >&6; } fi # Check if ffi is needed - if test "x$JVM_VARIANT_ZERO" = xtrue || test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then + if [[ " $JVM_VARIANTS " =~ " zero " ]] || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then NEEDS_LIB_FFI=true else NEEDS_LIB_FFI=false @@ -51132,14 +52820,26 @@ $as_echo "$has_static_libstdcxx" >&6; } # If dynamic wasn't requested, go with static unless it isn't available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libstdc++" >&5 $as_echo_n "checking how to link with libstdc++... " >&6; } - if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno || test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then + if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then LIBCXX="$LIBCXX -lstdc++" + # To help comparisons with old build, put stdc++ first in JVM_LIBS + JVM_LIBS="-lstdc++ $JVM_LIBS" + # Ideally, we should test stdc++ for the BUILD toolchain separately. For now + # just use the same setting as for the TARGET toolchain. + OPENJDK_BUILD_JVM_LIBS="-lstdc++ $OPENJDK_BUILD_JVM_LIBS" LDCXX="$CXX" STATIC_CXX_SETTING="STATIC_CXX=false" { $as_echo "$as_me:${as_lineno-$LINENO}: result: dynamic" >&5 $as_echo "dynamic" >&6; } else LIBCXX="$LIBCXX $STATIC_STDCXX_FLAGS" + JVM_LDFLAGS="$JVM_LDFLAGS -static-libgcc" + # To help comparisons with old build, put stdc++ first in JVM_LIBS + JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $JVM_LIBS" + # Ideally, we should test stdc++ for the BUILD toolchain separately. For now + # just use the same setting as for the TARGET toolchain. + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -static-libgcc" + OPENJDK_BUILD_JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $OPENJDK_BUILD_JVM_LIBS" LDCXX="$CC" STATIC_CXX_SETTING="STATIC_CXX=true" { $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5 @@ -61291,7 +62991,7 @@ $as_echo "$LIBFFI_WORKS" >&6; } - if test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then + if [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then # Extract the first word of "llvm-config", so it can be a program name with args. set dummy llvm-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -62017,9 +63717,143 @@ fi ############################################################################### + # Check whether --enable-new-hotspot-build was given. +if test "${enable_new_hotspot_build+set}" = set; then : + enableval=$enable_new_hotspot_build; +fi + + + if test "x$enable_new_hotspot_build" = "x" || test "x$enable_new_hotspot_build" = "xyes"; then + USE_NEW_HOTSPOT_BUILD=true + else + USE_NEW_HOTSPOT_BUILD=false + fi + + + case $HOTSPOT_DEBUG_LEVEL in + product ) + VARIANT="OPT" + FASTDEBUG="false" + DEBUG_CLASSFILES="false" + ;; + fastdebug ) + VARIANT="DBG" + FASTDEBUG="true" + DEBUG_CLASSFILES="true" + ;; + debug ) + VARIANT="DBG" + FASTDEBUG="false" + DEBUG_CLASSFILES="true" + ;; + optimized ) + VARIANT="OPT" + FASTDEBUG="false" + DEBUG_CLASSFILES="false" + ;; + esac + + + + + if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then + MACOSX_UNIVERSAL="true" + fi + + + + # Make sure JVM_VARIANTS_COMMA use minimal1 for backwards compatibility + JVM_VARIANTS_COMMA=`$ECHO ,$JVM_VARIANTS_OPT, | $SED -e 's/,minimal,/,minimal1,/'` + + JVM_VARIANT_SERVER=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,server,/!s/.*/false/g' -e '/,server,/s/.*/true/g'` + JVM_VARIANT_CLIENT=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,client,/!s/.*/false/g' -e '/,client,/s/.*/true/g'` + JVM_VARIANT_MINIMAL1=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,minimal1\?,/!s/.*/false/g' -e '/,minimal1\?,/s/.*/true/g'` + JVM_VARIANT_CORE=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,core,/!s/.*/false/g' -e '/,core,/s/.*/true/g'` + JVM_VARIANT_ZERO=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,zero,/!s/.*/false/g' -e '/,zero,/s/.*/true/g'` + JVM_VARIANT_ZEROSHARK=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,zeroshark,/!s/.*/false/g' -e '/,zeroshark,/s/.*/true/g'` + JVM_VARIANT_CUSTOM=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,custom,/!s/.*/false/g' -e '/,custom,/s/.*/true/g'` + + ##### + # Generate the legacy makefile targets for hotspot. + HOTSPOT_TARGET="" + + if test "x$JVM_VARIANT_SERVER" = xtrue; then + HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL} " + fi + + if test "x$JVM_VARIANT_CLIENT" = xtrue; then + HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}1 " + fi + + if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then + HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}minimal1 " + fi + + if test "x$JVM_VARIANT_ZERO" = xtrue; then + HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}zero " + fi + + if test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then + HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}shark " + fi + + if test "x$JVM_VARIANT_CORE" = xtrue; then + HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}core " + fi + + HOTSPOT_TARGET="$HOTSPOT_TARGET docs export_$HOTSPOT_DEBUG_LEVEL" + + # On Macosx universal binaries are produced, but they only contain + # 64 bit intel. This invalidates control of which jvms are built + # from configure, but only server is valid anyway. Fix this + # when hotspot makefiles are rewritten. + if test "x$MACOSX_UNIVERSAL" = xtrue; then + HOTSPOT_TARGET=universal_${HOTSPOT_DEBUG_LEVEL} + fi + HOTSPOT_MAKE_ARGS="$HOTSPOT_TARGET" + # Control wether Hotspot runs Queens test after build. + # Check whether --enable-hotspot-test-in-build was given. +if test "${enable_hotspot_test_in_build+set}" = set; then : + enableval=$enable_hotspot_test_in_build; +else + enable_hotspot_test_in_build=no +fi + + if test "x$enable_hotspot_test_in_build" = "xyes"; then + TEST_IN_BUILD=true + else + TEST_IN_BUILD=false + fi + + + if test "x$USE_NEW_HOTSPOT_BUILD" = xfalse; then + if test "x$JVM_VARIANT_CLIENT" = xtrue; then + if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + as_fn_error $? "You cannot build a client JVM for a 64-bit machine." "$LINENO" 5 + fi + fi + if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then + if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + as_fn_error $? "You cannot build a minimal JVM for a 64-bit machine." "$LINENO" 5 + fi + fi + if test "x$JVM_VARIANT_CUSTOM" = xtrue; then + as_fn_error $? "You cannot build a custom JVM using the old hotspot build system." "$LINENO" 5 + fi + fi + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if elliptic curve crypto implementation is present" >&5 $as_echo_n "checking if elliptic curve crypto implementation is present... " >&6; } @@ -63269,6 +65103,10 @@ $as_echo "no, forced" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, does not work effectively with icecc" >&5 $as_echo "no, does not work effectively with icecc" >&6; } USE_PRECOMPILED_HEADER=0 + elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, does not work with Solaris Studio" >&5 +$as_echo "no, does not work with Solaris Studio" >&6; } + USE_PRECOMPILED_HEADER=0 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -63689,6 +65527,32 @@ $as_echo "$OUTPUT_DIR_IS_LOCAL" >&6; } # At the end, call the custom hook. (Dummy macro if no custom sources available) +# This needs to be done after CUSTOM_LATE_HOOK since we can setup custom features. + + # Keep feature lists sorted and free of duplicates + JVM_FEATURES_server="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_server | $SORT -u))" + JVM_FEATURES_client="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_client | $SORT -u))" + JVM_FEATURES_core="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_core | $SORT -u))" + JVM_FEATURES_minimal="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_minimal | $SORT -u))" + JVM_FEATURES_zero="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_zero | $SORT -u))" + JVM_FEATURES_zeroshark="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_zeroshark | $SORT -u))" + JVM_FEATURES_custom="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_custom | $SORT -u))" + + # Validate features + for variant in $JVM_VARIANTS; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking JVM features for JVM variant '$variant'" >&5 +$as_echo_n "checking JVM features for JVM variant '$variant'... " >&6; } + features_var_name=JVM_FEATURES_$variant + JVM_FEATURES_TO_TEST=${!features_var_name} + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JVM_FEATURES_TO_TEST" >&5 +$as_echo "$JVM_FEATURES_TO_TEST" >&6; } + INVALID_FEATURES=`$GREP -Fvx "${VALID_JVM_FEATURES// /$'\n'}" <<< "${JVM_FEATURES_TO_TEST// /$'\n'}"` + if test "x$INVALID_FEATURES" != x; then + as_fn_error $? "Invalid JVM feature(s): $INVALID_FEATURES" "$LINENO" 5 + fi + done + + # We're messing a bit with internal autoconf variables to put the config.status # in the output directory instead of the current directory. CONFIG_STATUS="$CONFIGURESUPPORT_OUTPUTDIR/config.status" @@ -64912,7 +66776,7 @@ fi printf "* Debug level: $DEBUG_LEVEL\n" printf "* HS debug level: $HOTSPOT_DEBUG_LEVEL\n" printf "* JDK variant: $JDK_VARIANT\n" - printf "* JVM variants: $with_jvm_variants\n" + printf "* JVM variants: $JVM_VARIANTS\n" printf "* OpenJDK target: OS: $OPENJDK_TARGET_OS, CPU architecture: $OPENJDK_TARGET_CPU_ARCH, address length: $OPENJDK_TARGET_CPU_BITS\n" printf "* Version string: $VERSION_STRING ($VERSION_SHORT)\n" @@ -64938,7 +66802,7 @@ fi fi printf "\n" - if test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = "xyes"; then + if test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = "xtrue"; then printf "NOTE: You have requested to build more than one version of the JVM, which\n" printf "will result in longer build times.\n" printf "\n" diff --git a/common/autoconf/help.m4 b/common/autoconf/help.m4 index d0892c56256..e7ccdca3cf3 100644 --- a/common/autoconf/help.m4 +++ b/common/autoconf/help.m4 @@ -119,6 +119,8 @@ apt_help() { PKGHANDLER_COMMAND="sudo apt-get install libX11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev" ;; ccache) PKGHANDLER_COMMAND="sudo apt-get install ccache" ;; + dtrace) + PKGHANDLER_COMMAND="sudo apt-get install systemtap-sdt-dev" ;; esac } @@ -170,6 +172,13 @@ AC_DEFUN_ONCE([HELP_PRINT_ADDITIONAL_HELP_AND_EXIT], TOOLCHAIN_DESCRIPTION=${!toolchain_var_name} $PRINTF " %-10s %s\n" $toolchain "$TOOLCHAIN_DESCRIPTION" done + $PRINTF "\n" + + # Print available jvm features + $PRINTF "The following JVM features are available as arguments to --with-jvm-features.\n" + $PRINTF "Which are valid to use depends on the target platform.\n " + $PRINTF "%s " $VALID_JVM_FEATURES + $PRINTF "\n" # And now exit directly exit 0 @@ -206,7 +215,7 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS], printf "* Debug level: $DEBUG_LEVEL\n" printf "* HS debug level: $HOTSPOT_DEBUG_LEVEL\n" printf "* JDK variant: $JDK_VARIANT\n" - printf "* JVM variants: $with_jvm_variants\n" + printf "* JVM variants: $JVM_VARIANTS\n" printf "* OpenJDK target: OS: $OPENJDK_TARGET_OS, CPU architecture: $OPENJDK_TARGET_CPU_ARCH, address length: $OPENJDK_TARGET_CPU_BITS\n" printf "* Version string: $VERSION_STRING ($VERSION_SHORT)\n" @@ -232,7 +241,7 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS], fi printf "\n" - if test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = "xyes"; then + if test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = "xtrue"; then printf "NOTE: You have requested to build more than one version of the JVM, which\n" printf "will result in longer build times.\n" printf "\n" diff --git a/common/autoconf/hotspot-spec.gmk.in b/common/autoconf/hotspot-spec.gmk.in index 54b6ca2f9ed..50d790876a6 100644 --- a/common/autoconf/hotspot-spec.gmk.in +++ b/common/autoconf/hotspot-spec.gmk.in @@ -38,6 +38,16 @@ include $(BASE_SPEC) # Legacy defines controlled by the SUPPORT_HEADLESS and SUPPORT_HEADFUL options. @BUILD_HEADLESS@ +JVM_VARIANTS:=@JVM_VARIANTS_COMMA@ + +JVM_VARIANT_SERVER:=@JVM_VARIANT_SERVER@ +JVM_VARIANT_CLIENT:=@JVM_VARIANT_CLIENT@ +JVM_VARIANT_MINIMAL1:=@JVM_VARIANT_MINIMAL1@ +JVM_VARIANT_CORE:=@JVM_VARIANT_CORE@ +JVM_VARIANT_ZERO:=@JVM_VARIANT_ZERO@ +JVM_VARIANT_ZEROSHARK:=@JVM_VARIANT_ZEROSHARK@ +JVM_VARIANT_CUSTOM:=@JVM_VARIANT_HOTSPOT@ + # Legacy setting: OPT or DBG VARIANT:=@VARIANT@ # Legacy setting: true or false @@ -92,8 +102,7 @@ LLVM_LDFLAGS=@LLVM_LDFLAGS@ ALT_OUTPUTDIR=$(HOTSPOT_OUTPUTDIR) ALT_EXPORT_PATH=$(HOTSPOT_DIST) -JVM_INTERPRETER:=@JVM_INTERPRETER@ -ifeq ($(JVM_INTERPRETER), cpp) +ifeq ($(HOTSPOT_TARGET_CPU), zero) CC_INTERP=true endif diff --git a/common/autoconf/hotspot.m4 b/common/autoconf/hotspot.m4 index fe3eec0ecde..4fffa86983d 100644 --- a/common/autoconf/hotspot.m4 +++ b/common/autoconf/hotspot.m4 @@ -23,170 +23,344 @@ # questions. # -############################################################################### -# Check which interpreter of the JVM we want to build. -# Currently we have: -# template: Template interpreter (the default) -# cpp : C++ interpreter -AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_INTERPRETER], -[ - AC_ARG_WITH([jvm-interpreter], [AS_HELP_STRING([--with-jvm-interpreter], - [JVM interpreter to build (template, cpp) @<:@template@:>@])]) +# All valid JVM features, regardless of platform +VALID_JVM_FEATURES="compiler1 compiler2 zero shark minimal dtrace jvmti jvmci \ + fprof vm-structs jni-check services management all-gcs nmt cds static-build" - AC_MSG_CHECKING([which interpreter of the JVM to build]) - if test "x$with_jvm_interpreter" = x; then - JVM_INTERPRETER="template" - else - JVM_INTERPRETER="$with_jvm_interpreter" - fi - AC_MSG_RESULT([$JVM_INTERPRETER]) - - if test "x$JVM_INTERPRETER" != xtemplate && test "x$JVM_INTERPRETER" != xcpp; then - AC_MSG_ERROR([The available JVM interpreters are: template, cpp]) - fi - - AC_SUBST(JVM_INTERPRETER) -]) +# All valid JVM variants +VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom" ############################################################################### -# Check which variants of the JVM that we want to build. -# Currently we have: -# server: normal interpreter and a C2 or tiered C1/C2 compiler -# client: normal interpreter and C1 (no C2 compiler) (only 32-bit platforms) -# minimal1: reduced form of client with optional VM services and features stripped out -# zero: no machine code interpreter, no compiler -# zeroshark: zero interpreter and shark/llvm compiler backend -# core: interpreter only, no compiler (only works on some platforms) +# Check if the specified JVM variant should be built. To be used in shell if +# constructs, like this: +# if HOTSPOT_CHECK_JVM_VARIANT(server); then +# +# Only valid to use after HOTSPOT_SETUP_JVM_VARIANTS has setup variants. + +# Definition kept in one line to allow inlining in if statements. +# Additional [] needed to keep m4 from mangling shell constructs. +AC_DEFUN([HOTSPOT_CHECK_JVM_VARIANT], +[ [ [[ " $JVM_VARIANTS " =~ " $1 " ]] ] ]) + +############################################################################### +# Check if the specified JVM features are explicitly enabled. To be used in +# shell if constructs, like this: +# if HOTSPOT_CHECK_JVM_FEATURE(jvmti); then +# +# Only valid to use after HOTSPOT_SETUP_JVM_FEATURES has setup features. + +# Definition kept in one line to allow inlining in if statements. +# Additional [] needed to keep m4 from mangling shell constructs. +AC_DEFUN([HOTSPOT_CHECK_JVM_FEATURE], +[ [ [[ " $JVM_FEATURES " =~ " $1 " ]] ] ]) + +############################################################################### +# Check which variants of the JVM that we want to build. Available variants are: +# server: normal interpreter, and a tiered C1/C2 compiler +# client: normal interpreter, and C1 (no C2 compiler) +# minimal: reduced form of client with optional features stripped out +# core: normal interpreter only, no compiler +# zero: C++ based interpreter only, no compiler +# zeroshark: C++ based interpreter, and a llvm-based compiler +# custom: baseline JVM with no default features +# AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_VARIANTS], [ - AC_MSG_CHECKING([which variants of the JVM to build]) AC_ARG_WITH([jvm-variants], [AS_HELP_STRING([--with-jvm-variants], - [JVM variants (separated by commas) to build (server, client, minimal1, zero, zeroshark, core) @<:@server@:>@])]) + [JVM variants (separated by commas) to build (server,client,minimal,core,zero,zeroshark,custom) @<:@server@:>@])]) if test "x$with_jvm_variants" = x; then with_jvm_variants="server" fi + JVM_VARIANTS_OPT="$with_jvm_variants" - JVM_VARIANTS=",$with_jvm_variants," - TEST_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,//' -e 's/client,//' -e 's/minimal1,//' -e 's/zero,//' -e 's/zeroshark,//' -e 's/core,//'` - - if test "x$TEST_VARIANTS" != "x,"; then - AC_MSG_ERROR([The available JVM variants are: server, client, minimal1, zero, zeroshark, core]) - fi - AC_MSG_RESULT([$with_jvm_variants]) - - JVM_VARIANT_SERVER=`$ECHO "$JVM_VARIANTS" | $SED -e '/,server,/!s/.*/false/g' -e '/,server,/s/.*/true/g'` - JVM_VARIANT_CLIENT=`$ECHO "$JVM_VARIANTS" | $SED -e '/,client,/!s/.*/false/g' -e '/,client,/s/.*/true/g'` - JVM_VARIANT_MINIMAL1=`$ECHO "$JVM_VARIANTS" | $SED -e '/,minimal1,/!s/.*/false/g' -e '/,minimal1,/s/.*/true/g'` - JVM_VARIANT_ZERO=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zero,/!s/.*/false/g' -e '/,zero,/s/.*/true/g'` - JVM_VARIANT_ZEROSHARK=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zeroshark,/!s/.*/false/g' -e '/,zeroshark,/s/.*/true/g'` - JVM_VARIANT_CORE=`$ECHO "$JVM_VARIANTS" | $SED -e '/,core,/!s/.*/false/g' -e '/,core,/s/.*/true/g'` - - if test "x$JVM_VARIANT_CLIENT" = xtrue; then - if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then - AC_MSG_ERROR([You cannot build a client JVM for a 64-bit machine.]) - fi - fi - if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then - if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then - AC_MSG_ERROR([You cannot build a minimal JVM for a 64-bit machine.]) - fi - fi - - # Replace the commas with AND for use in the build directory name. - ANDED_JVM_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/^,//' -e 's/,$//' -e 's/,/AND/g'` - COUNT_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,/1/' -e 's/client,/1/' -e 's/minimal1,/1/' -e 's/zero,/1/' -e 's/zeroshark,/1/' -e 's/core,/1/'` - if test "x$COUNT_VARIANTS" != "x,1"; then - BUILDING_MULTIPLE_JVM_VARIANTS=yes + # Has the user listed more than one variant? + # Additional [] needed to keep m4 from mangling shell constructs. + if [ [[ "$JVM_VARIANTS_OPT" =~ "," ]] ]; then + BUILDING_MULTIPLE_JVM_VARIANTS=true else - BUILDING_MULTIPLE_JVM_VARIANTS=no + BUILDING_MULTIPLE_JVM_VARIANTS=false + fi + # Replace the commas with AND for use in the build directory name. + JVM_VARIANTS_WITH_AND=`$ECHO "$JVM_VARIANTS_OPT" | $SED -e 's/,/AND/g'` + + AC_MSG_CHECKING([which variants of the JVM to build]) + # JVM_VARIANTS is a space-separated list. + # Also use minimal, not minimal1 (which is kept for backwards compatibility). + JVM_VARIANTS=`$ECHO $JVM_VARIANTS_OPT | $SED -e 's/,/ /g' -e 's/minimal1/minimal/'` + AC_MSG_RESULT([$JVM_VARIANTS]) + + # Check that the selected variants are valid + + # grep filter function inspired by a comment to http://stackoverflow.com/a/1617326 + INVALID_VARIANTS=`$GREP -Fvx "${VALID_JVM_VARIANTS// /$'\n'}" <<< "${JVM_VARIANTS// /$'\n'}"` + if test "x$INVALID_VARIANTS" != x; then + AC_MSG_NOTICE([Unknown variant(s) specified: $INVALID_VARIANTS]) + AC_MSG_ERROR([The available JVM variants are: $VALID_JVM_VARIANTS]) fi - if test "x$JVM_VARIANT_ZERO" = xtrue && test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = xyes; then - AC_MSG_ERROR([You cannot build multiple variants with zero.]) + # All "special" variants share the same output directory ("server") + VALID_MULTIPLE_JVM_VARIANTS="server client minimal" + INVALID_MULTIPLE_VARIANTS=`$GREP -Fvx "${VALID_MULTIPLE_JVM_VARIANTS// /$'\n'}" <<< "${JVM_VARIANTS// /$'\n'}"` + if test "x$INVALID_MULTIPLE_VARIANTS" != x && test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = xtrue; then + AC_MSG_ERROR([You cannot build multiple variants with anything else than $VALID_MULTIPLE_JVM_VARIANTS.]) fi AC_SUBST(JVM_VARIANTS) - AC_SUBST(JVM_VARIANT_SERVER) - AC_SUBST(JVM_VARIANT_CLIENT) - AC_SUBST(JVM_VARIANT_MINIMAL1) - AC_SUBST(JVM_VARIANT_ZERO) - AC_SUBST(JVM_VARIANT_ZEROSHARK) - AC_SUBST(JVM_VARIANT_CORE) + AC_SUBST(VALID_JVM_VARIANTS) + + if HOTSPOT_CHECK_JVM_VARIANT(zero) || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + # zero behaves as a platform and rewrites these values. This is really weird. :( + # We are guaranteed that we do not build any other variants when building zero. + HOTSPOT_TARGET_CPU=zero + HOTSPOT_TARGET_CPU_ARCH=zero + fi +]) + +############################################################################### +# Check if dtrace should be enabled and has all prerequisites present. +# +AC_DEFUN_ONCE([HOTSPOT_SETUP_DTRACE], +[ + # Test for dtrace dependencies + AC_ARG_ENABLE([dtrace], [AS_HELP_STRING([--enable-dtrace@<:@=yes/no/auto@:>@], + [enable dtrace. Default is auto, where dtrace is enabled if all dependencies + are present.])]) + + DTRACE_DEP_MISSING=false + + AC_MSG_CHECKING([for dtrace tool]) + if test "x$DTRACE" != "x" && test -x "$DTRACE"; then + AC_MSG_RESULT([$DTRACE]) + else + AC_MSG_RESULT([not found, cannot build dtrace]) + DTRACE_DEP_MISSING=true + fi + + AC_CHECK_HEADERS([sys/sdt.h], [DTRACE_HEADERS_OK=yes],[DTRACE_HEADERS_OK=no]) + if test "x$DTRACE_HEADERS_OK" != "xyes"; then + DTRACE_DEP_MISSING=true + fi + + AC_MSG_CHECKING([if dtrace should be built]) + if test "x$enable_dtrace" = "xyes"; then + if test "x$DTRACE_DEP_MISSING" = "xtrue"; then + AC_MSG_RESULT([no, missing dependencies]) + HELP_MSG_MISSING_DEPENDENCY([dtrace]) + AC_MSG_ERROR([Cannot enable dtrace with missing dependencies. See above. $HELP_MSG]) + else + INCLUDE_DTRACE=true + AC_MSG_RESULT([yes, forced]) + fi + elif test "x$enable_dtrace" = "xno"; then + INCLUDE_DTRACE=false + AC_MSG_RESULT([no, forced]) + elif test "x$enable_dtrace" = "xauto" || test "x$enable_dtrace" = "x"; then + if test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK" != "xtrue"; then + INCLUDE_DTRACE=false + AC_MSG_RESULT([no, non-open linux build]) + elif test "x$DTRACE_DEP_MISSING" = "xtrue"; then + INCLUDE_DTRACE=false + AC_MSG_RESULT([no, missing dependencies]) + else + INCLUDE_DTRACE=true + AC_MSG_RESULT([yes, dependencies present]) + fi + else + AC_MSG_ERROR([Invalid value for --enable-dtrace: $enable_dtrace]) + fi + AC_SUBST(INCLUDE_DTRACE) +]) + +############################################################################### +# Set up all JVM features for each JVM variant. +# +AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES], +[ + # The user can in some cases supply additional jvm features. For the custom + # variant, this defines the entire variant. + AC_ARG_WITH([jvm-features], [AS_HELP_STRING([--with-jvm-features], + [additional JVM features to enable (separated by comma), use '--help' to show possible values @<:@none@:>@])]) + if test "x$with_jvm_features" != x; then + AC_MSG_CHECKING([additional JVM features]) + JVM_FEATURES=`$ECHO $with_jvm_features | $SED -e 's/,/ /g'` + AC_MSG_RESULT([$JVM_FEATURES]) + fi + + # Verify that dependencies are met for explicitly set features. + if HOTSPOT_CHECK_JVM_FEATURE(jvmti) && ! HOTSPOT_CHECK_JVM_FEATURE(services); then + AC_MSG_ERROR([Specified JVM feature 'jvmti' requires feature 'services']) + fi + + if HOTSPOT_CHECK_JVM_FEATURE(management) && ! HOTSPOT_CHECK_JVM_FEATURE(nmt); then + AC_MSG_ERROR([Specified JVM feature 'management' requires feature 'nmt']) + fi + + if HOTSPOT_CHECK_JVM_FEATURE(jvmci) && ! HOTSPOT_CHECK_JVM_FEATURE(compiler2); then + AC_MSG_ERROR([Specified JVM feature 'jvmci' requires feature 'compiler2']) + fi + + if HOTSPOT_CHECK_JVM_FEATURE(compiler2) && ! HOTSPOT_CHECK_JVM_FEATURE(all-gcs); then + AC_MSG_ERROR([Specified JVM feature 'compiler2' requires feature 'all-gcs']) + fi + + if HOTSPOT_CHECK_JVM_FEATURE(vm-structs) && ! HOTSPOT_CHECK_JVM_FEATURE(all-gcs); then + AC_MSG_ERROR([Specified JVM feature 'vm-structs' requires feature 'all-gcs']) + fi + + # Turn on additional features based on other parts of configure + if test "x$INCLUDE_DTRACE" = "xtrue"; then + JVM_FEATURES="$JVM_FEATURES dtrace" + else + if HOTSPOT_CHECK_JVM_FEATURE(dtrace); then + AC_MSG_ERROR([To enable dtrace, you must use --enable-dtrace]) + fi + fi + + if test "x$STATIC_BUILD" = "xtrue"; then + JVM_FEATURES="$JVM_FEATURES static-build" + else + if HOTSPOT_CHECK_JVM_FEATURE(static-build); then + AC_MSG_ERROR([To enable static-build, you must use --enable-static-build]) + fi + fi + + if ! HOTSPOT_CHECK_JVM_VARIANT(zero) && ! HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + if HOTSPOT_CHECK_JVM_FEATURE(zero); then + AC_MSG_ERROR([To enable zero/zeroshark, you must use --with-jvm-variants=zero/zeroshark]) + fi + fi + + if ! HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + if HOTSPOT_CHECK_JVM_FEATURE(shark); then + AC_MSG_ERROR([To enable shark, you must use --with-jvm-variants=zeroshark]) + fi + fi + + # Only enable jvmci on x86_64, sparcv9 and aarch64, and only on server. + if test "x$OPENJDK_TARGET_CPU" = "xx86_64" || \ + test "x$OPENJDK_TARGET_CPU" = "xsparcv9" || \ + test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then + JVM_FEATURES_jvmci="jvmci" + else + JVM_FEATURES_jvmci="" + fi + + # All variants but minimal (and custom) get these features + NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti fprof vm-structs jni-check services management all-gcs nmt cds" + + # Enable features depending on variant. + JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci" + JVM_FEATURES_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES" + JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES" + JVM_FEATURES_minimal="compiler1 minimal $JVM_FEATURES" + JVM_FEATURES_zero="zero $NON_MINIMAL_FEATURES $JVM_FEATURES" + JVM_FEATURES_zeroshark="zero shark $NON_MINIMAL_FEATURES $JVM_FEATURES" + JVM_FEATURES_custom="$JVM_FEATURES" + + AC_SUBST(JVM_FEATURES_server) + AC_SUBST(JVM_FEATURES_client) + AC_SUBST(JVM_FEATURES_core) + AC_SUBST(JVM_FEATURES_minimal) + AC_SUBST(JVM_FEATURES_zero) + AC_SUBST(JVM_FEATURES_zeroshark) + AC_SUBST(JVM_FEATURES_custom) + + # Used for verification of Makefiles by check-jvm-feature + AC_SUBST(VALID_JVM_FEATURES) + + # We don't support --with-jvm-interpreter anymore, use zero instead. + BASIC_DEPRECATED_ARG_WITH(jvm-interpreter) +]) + +############################################################################### +# Validate JVM features once all setup is complete, including custom setup. +# +AC_DEFUN_ONCE([HOTSPOT_VALIDATE_JVM_FEATURES], +[ + # Keep feature lists sorted and free of duplicates + JVM_FEATURES_server="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_server | $SORT -u))" + JVM_FEATURES_client="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_client | $SORT -u))" + JVM_FEATURES_core="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_core | $SORT -u))" + JVM_FEATURES_minimal="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_minimal | $SORT -u))" + JVM_FEATURES_zero="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_zero | $SORT -u))" + JVM_FEATURES_zeroshark="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_zeroshark | $SORT -u))" + JVM_FEATURES_custom="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_custom | $SORT -u))" + + # Validate features + for variant in $JVM_VARIANTS; do + AC_MSG_CHECKING([JVM features for JVM variant '$variant']) + features_var_name=JVM_FEATURES_$variant + JVM_FEATURES_TO_TEST=${!features_var_name} + AC_MSG_RESULT([$JVM_FEATURES_TO_TEST]) + INVALID_FEATURES=`$GREP -Fvx "${VALID_JVM_FEATURES// /$'\n'}" <<< "${JVM_FEATURES_TO_TEST// /$'\n'}"` + if test "x$INVALID_FEATURES" != x; then + AC_MSG_ERROR([Invalid JVM feature(s): $INVALID_FEATURES]) + fi + done +]) + +############################################################################### +# Support for old hotspot build. Remove once new hotspot build has proven +# to work satisfactory. +# +AC_DEFUN_ONCE([HOTSPOT_SETUP_LEGACY_BUILD], +[ + AC_ARG_ENABLE(new-hotspot-build, [AS_HELP_STRING([--disable-new-hotspot-build], + [disable the new hotspot build system (use the old) @<:@enabled@:>@])]) + + if test "x$enable_new_hotspot_build" = "x" || test "x$enable_new_hotspot_build" = "xyes"; then + USE_NEW_HOTSPOT_BUILD=true + else + USE_NEW_HOTSPOT_BUILD=false + fi + AC_SUBST(USE_NEW_HOTSPOT_BUILD) + + case $HOTSPOT_DEBUG_LEVEL in + product ) + VARIANT="OPT" + FASTDEBUG="false" + DEBUG_CLASSFILES="false" + ;; + fastdebug ) + VARIANT="DBG" + FASTDEBUG="true" + DEBUG_CLASSFILES="true" + ;; + debug ) + VARIANT="DBG" + FASTDEBUG="false" + DEBUG_CLASSFILES="true" + ;; + optimized ) + VARIANT="OPT" + FASTDEBUG="false" + DEBUG_CLASSFILES="false" + ;; + esac + AC_SUBST(VARIANT) + AC_SUBST(FASTDEBUG) + AC_SUBST(DEBUG_CLASSFILES) if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then MACOSX_UNIVERSAL="true" fi AC_SUBST(MACOSX_UNIVERSAL) -]) + # Make sure JVM_VARIANTS_COMMA use minimal1 for backwards compatibility + JVM_VARIANTS_COMMA=`$ECHO ,$JVM_VARIANTS_OPT, | $SED -e 's/,minimal,/,minimal1,/'` -############################################################################### -# Setup legacy vars/targets and new vars to deal with different debug levels. -# -# release: no debug information, all optimizations, no asserts. -# optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'. -# fastdebug: debug information (-g), all optimizations, all asserts -# slowdebug: debug information (-g), no optimizations, all asserts -# -AC_DEFUN_ONCE([HOTSPOT_SETUP_DEBUG_LEVEL], -[ - case $DEBUG_LEVEL in - release ) - VARIANT="OPT" - FASTDEBUG="false" - DEBUG_CLASSFILES="false" - BUILD_VARIANT_RELEASE="" - HOTSPOT_DEBUG_LEVEL="product" - HOTSPOT_EXPORT="product" - ;; - fastdebug ) - VARIANT="DBG" - FASTDEBUG="true" - DEBUG_CLASSFILES="true" - BUILD_VARIANT_RELEASE="-fastdebug" - HOTSPOT_DEBUG_LEVEL="fastdebug" - HOTSPOT_EXPORT="fastdebug" - ;; - slowdebug ) - VARIANT="DBG" - FASTDEBUG="false" - DEBUG_CLASSFILES="true" - BUILD_VARIANT_RELEASE="-debug" - HOTSPOT_DEBUG_LEVEL="debug" - HOTSPOT_EXPORT="debug" - ;; - optimized ) - VARIANT="OPT" - FASTDEBUG="false" - DEBUG_CLASSFILES="false" - BUILD_VARIANT_RELEASE="-optimized" - HOTSPOT_DEBUG_LEVEL="optimized" - HOTSPOT_EXPORT="optimized" - ;; - esac - - # The debug level 'optimized' is a little special because it is currently only - # applicable to the HotSpot build where it means to build a completely - # optimized version of the VM without any debugging code (like for the - # 'release' debug level which is called 'product' in the HotSpot build) but - # with the exception that it can contain additional code which is otherwise - # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to - # test new and/or experimental features which are not intended for customer - # shipment. Because these new features need to be tested and benchmarked in - # real world scenarios, we want to build the containing JDK at the 'release' - # debug level. - if test "x$DEBUG_LEVEL" = xoptimized; then - DEBUG_LEVEL="release" - fi + JVM_VARIANT_SERVER=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,server,/!s/.*/false/g' -e '/,server,/s/.*/true/g'` + JVM_VARIANT_CLIENT=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,client,/!s/.*/false/g' -e '/,client,/s/.*/true/g'` + JVM_VARIANT_MINIMAL1=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,minimal1\?,/!s/.*/false/g' -e '/,minimal1\?,/s/.*/true/g'` + JVM_VARIANT_CORE=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,core,/!s/.*/false/g' -e '/,core,/s/.*/true/g'` + JVM_VARIANT_ZERO=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,zero,/!s/.*/false/g' -e '/,zero,/s/.*/true/g'` + JVM_VARIANT_ZEROSHARK=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,zeroshark,/!s/.*/false/g' -e '/,zeroshark,/s/.*/true/g'` + JVM_VARIANT_CUSTOM=`$ECHO "$JVM_VARIANTS_COMMA" | $SED -e '/,custom,/!s/.*/false/g' -e '/,custom,/s/.*/true/g'` ##### # Generate the legacy makefile targets for hotspot. - # The hotspot api for selecting the build artifacts, really, needs to be improved. - # JDK-7195896 will fix this on the hotspot side by using the JVM_VARIANT_* variables to - # determine what needs to be built. All we will need to set here is all_product, all_fastdebug etc - # But until then ... HOTSPOT_TARGET="" if test "x$JVM_VARIANT_SERVER" = xtrue; then @@ -213,27 +387,19 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_DEBUG_LEVEL], HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}core " fi - HOTSPOT_TARGET="$HOTSPOT_TARGET docs export_$HOTSPOT_EXPORT" + HOTSPOT_TARGET="$HOTSPOT_TARGET docs export_$HOTSPOT_DEBUG_LEVEL" # On Macosx universal binaries are produced, but they only contain # 64 bit intel. This invalidates control of which jvms are built # from configure, but only server is valid anyway. Fix this # when hotspot makefiles are rewritten. if test "x$MACOSX_UNIVERSAL" = xtrue; then - HOTSPOT_TARGET=universal_${HOTSPOT_EXPORT} + HOTSPOT_TARGET=universal_${HOTSPOT_DEBUG_LEVEL} fi - ##### + HOTSPOT_MAKE_ARGS="$HOTSPOT_TARGET" + AC_SUBST(HOTSPOT_MAKE_ARGS) - AC_SUBST(DEBUG_LEVEL) - AC_SUBST(VARIANT) - AC_SUBST(FASTDEBUG) - AC_SUBST(DEBUG_CLASSFILES) - AC_SUBST(BUILD_VARIANT_RELEASE) -]) - -AC_DEFUN_ONCE([HOTSPOT_SETUP_HOTSPOT_OPTIONS], -[ # Control wether Hotspot runs Queens test after build. AC_ARG_ENABLE([hotspot-test-in-build], [AS_HELP_STRING([--enable-hotspot-test-in-build], [run the Queens test after Hotspot build @<:@disabled@:>@])],, @@ -244,10 +410,29 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_HOTSPOT_OPTIONS], TEST_IN_BUILD=false fi AC_SUBST(TEST_IN_BUILD) -]) -AC_DEFUN_ONCE([HOTSPOT_SETUP_BUILD_TWEAKS], -[ - HOTSPOT_MAKE_ARGS="$HOTSPOT_TARGET" - AC_SUBST(HOTSPOT_MAKE_ARGS) + if test "x$USE_NEW_HOTSPOT_BUILD" = xfalse; then + if test "x$JVM_VARIANT_CLIENT" = xtrue; then + if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + AC_MSG_ERROR([You cannot build a client JVM for a 64-bit machine.]) + fi + fi + if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then + if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + AC_MSG_ERROR([You cannot build a minimal JVM for a 64-bit machine.]) + fi + fi + if test "x$JVM_VARIANT_CUSTOM" = xtrue; then + AC_MSG_ERROR([You cannot build a custom JVM using the old hotspot build system.]) + fi + fi + + AC_SUBST(JVM_VARIANTS_COMMA) + AC_SUBST(JVM_VARIANT_SERVER) + AC_SUBST(JVM_VARIANT_CLIENT) + AC_SUBST(JVM_VARIANT_MINIMAL1) + AC_SUBST(JVM_VARIANT_HOTSPOT) + AC_SUBST(JVM_VARIANT_ZERO) + AC_SUBST(JVM_VARIANT_ZEROSHARK) + AC_SUBST(JVM_VARIANT_CORE) ]) diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index 3c677d8adde..0b45cbc877e 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -81,6 +81,31 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], test "x$DEBUG_LEVEL" != xslowdebug; then AC_MSG_ERROR([Allowed debug levels are: release, fastdebug, slowdebug and optimized]) fi + + # Translate DEBUG_LEVEL to debug level used by Hotspot + HOTSPOT_DEBUG_LEVEL="$DEBUG_LEVEL" + if test "x$DEBUG_LEVEL" = xrelease; then + HOTSPOT_DEBUG_LEVEL="product" + elif test "x$DEBUG_LEVEL" = xslowdebug; then + HOTSPOT_DEBUG_LEVEL="debug" + fi + + if test "x$DEBUG_LEVEL" = xoptimized; then + # The debug level 'optimized' is a little special because it is currently only + # applicable to the HotSpot build where it means to build a completely + # optimized version of the VM without any debugging code (like for the + # 'release' debug level which is called 'product' in the HotSpot build) but + # with the exception that it can contain additional code which is otherwise + # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to + # test new and/or experimental features which are not intended for customer + # shipment. Because these new features need to be tested and benchmarked in + # real world scenarios, we want to build the containing JDK at the 'release' + # debug level. + DEBUG_LEVEL="release" + fi + + AC_SUBST(HOTSPOT_DEBUG_LEVEL) + AC_SUBST(DEBUG_LEVEL) ]) ############################################################################### @@ -178,10 +203,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], # Should we build the serviceability agent (SA)? INCLUDE_SA=true - if test "x$JVM_VARIANT_ZERO" = xtrue ; then - INCLUDE_SA=false - fi - if test "x$JVM_VARIANT_ZEROSHARK" = xtrue ; then + if HOTSPOT_CHECK_JVM_VARIANT(zero) || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then INCLUDE_SA=false fi if test "x$OPENJDK_TARGET_OS" = xaix ; then diff --git a/common/autoconf/jdk-version.m4 b/common/autoconf/jdk-version.m4 index 2dc63865c49..3b2fbfb60f1 100644 --- a/common/autoconf/jdk-version.m4 +++ b/common/autoconf/jdk-version.m4 @@ -72,6 +72,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_SUBST(PRODUCT_SUFFIX) AC_SUBST(JDK_RC_PLATFORM_NAME) AC_SUBST(COMPANY_NAME) + AC_SUBST(HOTSPOT_VM_DISTRO) AC_SUBST(MACOSX_BUNDLE_NAME_BASE) AC_SUBST(MACOSX_BUNDLE_ID_BASE) diff --git a/common/autoconf/lib-std.m4 b/common/autoconf/lib-std.m4 index d3f94609630..6fa0b4844af 100644 --- a/common/autoconf/lib-std.m4 +++ b/common/autoconf/lib-std.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -88,13 +88,25 @@ AC_DEFUN_ONCE([LIB_SETUP_STD_LIBS], # If dynamic was requested, it's available since it would fail above otherwise. # If dynamic wasn't requested, go with static unless it isn't available. AC_MSG_CHECKING([how to link with libstdc++]) - if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno || test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then + if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then LIBCXX="$LIBCXX -lstdc++" + # To help comparisons with old build, put stdc++ first in JVM_LIBS + JVM_LIBS="-lstdc++ $JVM_LIBS" + # Ideally, we should test stdc++ for the BUILD toolchain separately. For now + # just use the same setting as for the TARGET toolchain. + OPENJDK_BUILD_JVM_LIBS="-lstdc++ $OPENJDK_BUILD_JVM_LIBS" LDCXX="$CXX" STATIC_CXX_SETTING="STATIC_CXX=false" AC_MSG_RESULT([dynamic]) else LIBCXX="$LIBCXX $STATIC_STDCXX_FLAGS" + JVM_LDFLAGS="$JVM_LDFLAGS -static-libgcc" + # To help comparisons with old build, put stdc++ first in JVM_LIBS + JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $JVM_LIBS" + # Ideally, we should test stdc++ for the BUILD toolchain separately. For now + # just use the same setting as for the TARGET toolchain. + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -static-libgcc" + OPENJDK_BUILD_JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $OPENJDK_BUILD_JVM_LIBS" LDCXX="$CC" STATIC_CXX_SETTING="STATIC_CXX=true" AC_MSG_RESULT([static]) diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4 index a6a8bd4f19b..e1e91d678d6 100644 --- a/common/autoconf/libraries.m4 +++ b/common/autoconf/libraries.m4 @@ -74,7 +74,7 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES], fi # Check if ffi is needed - if test "x$JVM_VARIANT_ZERO" = xtrue || test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then + if HOTSPOT_CHECK_JVM_VARIANT(zero) || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then NEEDS_LIB_FFI=true else NEEDS_LIB_FFI=false @@ -102,7 +102,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES], ################################################################################ AC_DEFUN_ONCE([LIB_SETUP_LLVM], [ - if test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then + if HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then AC_CHECK_PROG([LLVM_CONFIG], [llvm-config], [llvm-config]) if test "x$LLVM_CONFIG" != xllvm-config; then diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index fe5a201ecd9..587f80dbcd5 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -273,169 +273,169 @@ AC_DEFUN([PLATFORM_SETUP_TARGET_CPU_BITS], # Setup the legacy variables, for controlling the old makefiles. # AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS], +[ + PLATFORM_SETUP_LEGACY_VARS_HELPER([TARGET]) + PLATFORM_SETUP_LEGACY_VARS_HELPER([BUILD]) + + # ZERO_ARCHDEF is used to enable architecture-specific code. + # This is used in legacy hotspot build. + ZERO_ARCHDEF="$HOTSPOT_TARGET_CPU_DEFINE" + AC_SUBST(ZERO_ARCHDEF) + +]) + +# $1 - Either TARGET or BUILD to setup the variables for. +AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], [ # Also store the legacy naming of the cpu. # Ie i586 and amd64 instead of x86 and x86_64 - OPENJDK_TARGET_CPU_LEGACY="$OPENJDK_TARGET_CPU" - if test "x$OPENJDK_TARGET_CPU" = xx86; then - OPENJDK_TARGET_CPU_LEGACY="i586" - elif test "x$OPENJDK_TARGET_OS" != xmacosx && test "x$OPENJDK_TARGET_CPU" = xx86_64; then + OPENJDK_$1_CPU_LEGACY="$OPENJDK_$1_CPU" + if test "x$OPENJDK_$1_CPU" = xx86; then + OPENJDK_$1_CPU_LEGACY="i586" + elif test "x$OPENJDK_$1_OS" != xmacosx && test "x$OPENJDK_$1_CPU" = xx86_64; then # On all platforms except MacOSX replace x86_64 with amd64. - OPENJDK_TARGET_CPU_LEGACY="amd64" + OPENJDK_$1_CPU_LEGACY="amd64" fi - AC_SUBST(OPENJDK_TARGET_CPU_LEGACY) + AC_SUBST(OPENJDK_$1_CPU_LEGACY) # And the second legacy naming of the cpu. # Ie i386 and amd64 instead of x86 and x86_64. - OPENJDK_TARGET_CPU_LEGACY_LIB="$OPENJDK_TARGET_CPU" - if test "x$OPENJDK_TARGET_CPU" = xx86; then - OPENJDK_TARGET_CPU_LEGACY_LIB="i386" - elif test "x$OPENJDK_TARGET_CPU" = xx86_64; then - OPENJDK_TARGET_CPU_LEGACY_LIB="amd64" + OPENJDK_$1_CPU_LEGACY_LIB="$OPENJDK_$1_CPU" + if test "x$OPENJDK_$1_CPU" = xx86; then + OPENJDK_$1_CPU_LEGACY_LIB="i386" + elif test "x$OPENJDK_$1_CPU" = xx86_64; then + OPENJDK_$1_CPU_LEGACY_LIB="amd64" fi - AC_SUBST(OPENJDK_TARGET_CPU_LEGACY_LIB) + AC_SUBST(OPENJDK_$1_CPU_LEGACY_LIB) # This is the name of the cpu (but using i386 and amd64 instead of # x86 and x86_64, respectively), preceeded by a /, to be used when # locating libraries. On macosx, it's empty, though. - OPENJDK_TARGET_CPU_LIBDIR="/$OPENJDK_TARGET_CPU_LEGACY_LIB" - if test "x$OPENJDK_TARGET_OS" = xmacosx; then - OPENJDK_TARGET_CPU_LIBDIR="" + OPENJDK_$1_CPU_LIBDIR="/$OPENJDK_$1_CPU_LEGACY_LIB" + if test "x$OPENJDK_$1_OS" = xmacosx; then + OPENJDK_$1_CPU_LIBDIR="" fi - AC_SUBST(OPENJDK_TARGET_CPU_LIBDIR) + AC_SUBST(OPENJDK_$1_CPU_LIBDIR) - # Now do the same for OPENJDK_BUILD_CPU... - # Also store the legacy naming of the cpu. - # Ie i586 and amd64 instead of x86 and x86_64 - OPENJDK_BUILD_CPU_LEGACY="$OPENJDK_BUILD_CPU" - if test "x$OPENJDK_BUILD_CPU" = xx86; then - OPENJDK_BUILD_CPU_LEGACY="i586" - elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then - # On all platforms except MacOSX replace x86_64 with amd64. - OPENJDK_BUILD_CPU_LEGACY="amd64" - fi - AC_SUBST(OPENJDK_BUILD_CPU_LEGACY) - - # And the second legacy naming of the cpu. - # Ie i386 and amd64 instead of x86 and x86_64. - OPENJDK_BUILD_CPU_LEGACY_LIB="$OPENJDK_BUILD_CPU" - if test "x$OPENJDK_BUILD_CPU" = xx86; then - OPENJDK_BUILD_CPU_LEGACY_LIB="i386" - elif test "x$OPENJDK_BUILD_CPU" = xx86_64; then - OPENJDK_BUILD_CPU_LEGACY_LIB="amd64" - fi - AC_SUBST(OPENJDK_BUILD_CPU_LEGACY_LIB) - - # This is the name of the cpu (but using i386 and amd64 instead of - # x86 and x86_64, respectively), preceeded by a /, to be used when - # locating libraries. On macosx, it's empty, though. - OPENJDK_BUILD_CPU_LIBDIR="/$OPENJDK_BUILD_CPU_LEGACY_LIB" - if test "x$OPENJDK_BUILD_OS" = xmacosx; then - OPENJDK_BUILD_CPU_LIBDIR="" - fi - AC_SUBST(OPENJDK_BUILD_CPU_LIBDIR) - - # OPENJDK_TARGET_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to + # OPENJDK_$1_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to # /amd64 or /sparcv9. This string is appended to some library paths, like this: - # /usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libexample.so - OPENJDK_TARGET_CPU_ISADIR="" - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - if test "x$OPENJDK_TARGET_CPU" = xx86_64; then - OPENJDK_TARGET_CPU_ISADIR="/amd64" - elif test "x$OPENJDK_TARGET_CPU" = xsparcv9; then - OPENJDK_TARGET_CPU_ISADIR="/sparcv9" + # /usr/lib${OPENJDK_$1_CPU_ISADIR}/libexample.so + OPENJDK_$1_CPU_ISADIR="" + if test "x$OPENJDK_$1_OS" = xsolaris; then + if test "x$OPENJDK_$1_CPU" = xx86_64; then + OPENJDK_$1_CPU_ISADIR="/amd64" + elif test "x$OPENJDK_$1_CPU" = xsparcv9; then + OPENJDK_$1_CPU_ISADIR="/sparcv9" fi fi - AC_SUBST(OPENJDK_TARGET_CPU_ISADIR) + AC_SUBST(OPENJDK_$1_CPU_ISADIR) - # Setup OPENJDK_TARGET_CPU_OSARCH, which is used to set the os.arch Java system property - OPENJDK_TARGET_CPU_OSARCH="$OPENJDK_TARGET_CPU" - if test "x$OPENJDK_TARGET_OS" = xlinux && test "x$OPENJDK_TARGET_CPU" = xx86; then + # Setup OPENJDK_$1_CPU_OSARCH, which is used to set the os.arch Java system property + OPENJDK_$1_CPU_OSARCH="$OPENJDK_$1_CPU" + if test "x$OPENJDK_$1_OS" = xlinux && test "x$OPENJDK_$1_CPU" = xx86; then # On linux only, we replace x86 with i386. - OPENJDK_TARGET_CPU_OSARCH="i386" - elif test "x$OPENJDK_TARGET_OS" != xmacosx && test "x$OPENJDK_TARGET_CPU" = xx86_64; then + OPENJDK_$1_CPU_OSARCH="i386" + elif test "x$OPENJDK_$1_OS" != xmacosx && test "x$OPENJDK_$1_CPU" = xx86_64; then # On all platforms except macosx, we replace x86_64 with amd64. - OPENJDK_TARGET_CPU_OSARCH="amd64" + OPENJDK_$1_CPU_OSARCH="amd64" fi - AC_SUBST(OPENJDK_TARGET_CPU_OSARCH) + AC_SUBST(OPENJDK_$1_CPU_OSARCH) - OPENJDK_TARGET_CPU_JLI="$OPENJDK_TARGET_CPU" - if test "x$OPENJDK_TARGET_CPU" = xx86; then - OPENJDK_TARGET_CPU_JLI="i386" - elif test "x$OPENJDK_TARGET_OS" != xmacosx && test "x$OPENJDK_TARGET_CPU" = xx86_64; then + OPENJDK_$1_CPU_JLI="$OPENJDK_$1_CPU" + if test "x$OPENJDK_$1_CPU" = xx86; then + OPENJDK_$1_CPU_JLI="i386" + elif test "x$OPENJDK_$1_OS" != xmacosx && test "x$OPENJDK_$1_CPU" = xx86_64; then # On all platforms except macosx, we replace x86_64 with amd64. - OPENJDK_TARGET_CPU_JLI="amd64" + OPENJDK_$1_CPU_JLI="amd64" fi # Now setup the -D flags for building libjli. - OPENJDK_TARGET_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_TARGET_CPU_JLI\"'" - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - if test "x$OPENJDK_TARGET_CPU_ARCH" = xsparc; then - OPENJDK_TARGET_CPU_JLI_CFLAGS="$OPENJDK_TARGET_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'" - elif test "x$OPENJDK_TARGET_CPU_ARCH" = xx86; then - OPENJDK_TARGET_CPU_JLI_CFLAGS="$OPENJDK_TARGET_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'" + OPENJDK_$1_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_$1_CPU_JLI\"'" + if test "x$OPENJDK_$1_OS" = xsolaris; then + if test "x$OPENJDK_$1_CPU_ARCH" = xsparc; then + OPENJDK_$1_CPU_JLI_CFLAGS="$OPENJDK_$1_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'" + elif test "x$OPENJDK_$1_CPU_ARCH" = xx86; then + OPENJDK_$1_CPU_JLI_CFLAGS="$OPENJDK_$1_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'" fi fi - AC_SUBST(OPENJDK_TARGET_CPU_JLI_CFLAGS) + AC_SUBST(OPENJDK_$1_CPU_JLI_CFLAGS) - OPENJDK_BUILD_CPU_JLI="$OPENJDK_BUILD_CPU" - if test "x$OPENJDK_BUILD_CPU" = xx86; then - OPENJDK_BUILD_CPU_JLI="i386" - elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then - # On all platforms except macosx, we replace x86_64 with amd64. - OPENJDK_BUILD_CPU_JLI="amd64" - fi - # Now setup the -D flags for building libjli. - OPENJDK_BUILD_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_BUILD_CPU_JLI\"'" - if test "x$OPENJDK_BUILD_OS" = xsolaris; then - if test "x$OPENJDK_BUILD_CPU_ARCH" = xsparc; then - OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'" - elif test "x$OPENJDK_BUILD_CPU_ARCH" = xx86; then - OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'" - fi - fi - AC_SUBST(OPENJDK_BUILD_CPU_JLI_CFLAGS) - - if test "x$OPENJDK_TARGET_OS" = xmacosx; then - OPENJDK_TARGET_OS_EXPORT_DIR=macosx + if test "x$OPENJDK_$1_OS" = xmacosx; then + OPENJDK_$1_OS_EXPORT_DIR=macosx else - OPENJDK_TARGET_OS_EXPORT_DIR=${OPENJDK_TARGET_OS_TYPE} + OPENJDK_$1_OS_EXPORT_DIR=${OPENJDK_$1_OS_TYPE} fi - AC_SUBST(OPENJDK_TARGET_OS_EXPORT_DIR) + AC_SUBST(OPENJDK_$1_OS_EXPORT_DIR) - if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + if test "x$OPENJDK_$1_CPU_BITS" = x64; then A_LP64="LP64:=" # -D_LP64=1 is only set on linux and mac. Setting on windows causes diff in # unpack200.exe - if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xmacosx; then - ADD_LP64="-D_LP64=1" + if test "x$OPENJDK_$1_OS" = xlinux || test "x$OPENJDK_$1_OS" = xmacosx; then + OPENJDK_$1_ADD_LP64="-D_LP64=1" fi fi AC_SUBST(LP64,$A_LP64) - if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then - if test "x$OPENJDK_BUILD_OS" = xlinux || test "x$OPENJDK_BUILD_OS" = xmacosx; then - OPENJDK_BUILD_ADD_LP64="-D_LP64=1" - fi - fi if test "x$COMPILE_TYPE" = "xcross"; then # FIXME: ... or should this include reduced builds..? - DEFINE_CROSS_COMPILE_ARCH="CROSS_COMPILE_ARCH:=$OPENJDK_TARGET_CPU_LEGACY" + DEFINE_CROSS_COMPILE_ARCH="CROSS_COMPILE_ARCH:=$OPENJDK_$1_CPU_LEGACY" else DEFINE_CROSS_COMPILE_ARCH="" fi AC_SUBST(DEFINE_CROSS_COMPILE_ARCH) - # ZERO_ARCHDEF is used to enable architecture-specific code - case "${OPENJDK_TARGET_CPU}" in - ppc) ZERO_ARCHDEF=PPC32 ;; - ppc64) ZERO_ARCHDEF=PPC64 ;; - s390*) ZERO_ARCHDEF=S390 ;; - sparc*) ZERO_ARCHDEF=SPARC ;; - x86_64*) ZERO_ARCHDEF=AMD64 ;; - x86) ZERO_ARCHDEF=IA32 ;; - *) ZERO_ARCHDEF=$(echo "${OPENJDK_TARGET_CPU_LEGACY_LIB}" | tr a-z A-Z) - esac - AC_SUBST(ZERO_ARCHDEF) + # Convert openjdk platform names to hotspot names + + HOTSPOT_$1_OS=${OPENJDK_$1_OS} + if test "x$OPENJDK_$1_OS" = xmacosx; then + HOTSPOT_$1_OS=bsd + fi + AC_SUBST(HOTSPOT_$1_OS) + + HOTSPOT_$1_OS_TYPE=${OPENJDK_$1_OS_TYPE} + if test "x$OPENJDK_$1_OS_TYPE" = xunix; then + HOTSPOT_$1_OS_TYPE=posix + fi + AC_SUBST(HOTSPOT_$1_OS_TYPE) + + HOTSPOT_$1_CPU=${OPENJDK_$1_CPU} + if test "x$OPENJDK_$1_CPU" = xx86; then + HOTSPOT_$1_CPU=x86_32 + elif test "x$OPENJDK_$1_CPU" = xsparcv9; then + HOTSPOT_$1_CPU=sparc + elif test "x$OPENJDK_$1_CPU" = xppc64; then + HOTSPOT_$1_CPU=ppc_64 + fi + AC_SUBST(HOTSPOT_$1_CPU) + + # This is identical with OPENJDK_*, but define anyway for consistency. + HOTSPOT_$1_CPU_ARCH=${OPENJDK_$1_CPU_ARCH} + AC_SUBST(HOTSPOT_$1_CPU_ARCH) + + # Setup HOTSPOT_$1_CPU_DEFINE + if test "x$OPENJDK_$1_CPU" = xx86; then + HOTSPOT_$1_CPU_DEFINE=IA32 + elif test "x$OPENJDK_$1_CPU" = xx86_64; then + HOTSPOT_$1_CPU_DEFINE=AMD64 + elif test "x$OPENJDK_$1_CPU" = xsparcv9; then + HOTSPOT_$1_CPU_DEFINE=SPARC + elif test "x$OPENJDK_$1_CPU" = xaarch64; then + HOTSPOT_$1_CPU_DEFINE=AARCH64 + elif test "x$OPENJDK_$1_CPU" = xppc64; then + HOTSPOT_$1_CPU_DEFINE=PPC64 + + # The cpu defines below are for zero, we don't support them directly. + elif test "x$OPENJDK_$1_CPU" = xsparc; then + HOTSPOT_$1_CPU_DEFINE=SPARC + elif test "x$OPENJDK_$1_CPU" = xppc; then + HOTSPOT_$1_CPU_DEFINE=PPC32 + elif test "x$OPENJDK_$1_CPU" = xs390; then + HOTSPOT_$1_CPU_DEFINE=S390 + elif test "x$OPENJDK_$1_CPU" = ss390x; then + HOTSPOT_$1_CPU_DEFINE=S390 + fi + AC_SUBST(HOTSPOT_$1_CPU_DEFINE) + ]) AC_DEFUN([PLATFORM_SET_RELEASE_FILE_OS_VALUES], @@ -521,6 +521,10 @@ AC_DEFUN([PLATFORM_SET_COMPILER_TARGET_BITS_FLAGS], CFLAGS_JDK="${CFLAGS_JDK}${ADDED_CFLAGS}" CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}" LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}" + + JVM_CFLAGS="$JVM_CFLAGS $ADDED_CFLAGS" + JVM_LDFLAGS="$JVM_LDFLAGS $ADDED_LDFLAGS" + JVM_ASFLAGS="$JVM_ASFLAGS $ADDED_CFLAGS" ]) AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_TARGET_BITS], @@ -542,6 +546,11 @@ AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_TARGET_BITS], PLATFORM_SET_COMPILER_TARGET_BITS_FLAGS fi fi + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + JVM_CFLAGS="$JVM_CFLAGS ${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" + JVM_LDFLAGS="$JVM_LDFLAGS ${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" + JVM_ASFLAGS="$JVM_ASFLAGS ${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" + fi # Make compilation sanity check AC_CHECK_HEADERS([stdio.h], , [ diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 0af5e6d0e2d..a30346427a2 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -82,6 +82,13 @@ OPENJDK_TARGET_CPU_OSARCH:=@OPENJDK_TARGET_CPU_OSARCH@ OPENJDK_TARGET_CPU_JLI_CFLAGS:=@OPENJDK_TARGET_CPU_JLI_CFLAGS@ OPENJDK_TARGET_OS_EXPORT_DIR:=@OPENJDK_TARGET_OS_EXPORT_DIR@ +HOTSPOT_TARGET_OS := @HOTSPOT_TARGET_OS@ +HOTSPOT_TARGET_OS_TYPE := @HOTSPOT_TARGET_OS_TYPE@ + +HOTSPOT_TARGET_CPU := @HOTSPOT_TARGET_CPU@ +HOTSPOT_TARGET_CPU_ARCH := @HOTSPOT_TARGET_CPU_ARCH@ +HOTSPOT_TARGET_CPU_DEFINE := @HOTSPOT_TARGET_CPU_DEFINE@ + # We are building on this build system. # When not cross-compiling, it is the same as the target. OPENJDK_BUILD_OS:=@OPENJDK_BUILD_OS@ @@ -192,6 +199,7 @@ PRODUCT_NAME:=@PRODUCT_NAME@ PRODUCT_SUFFIX:=@PRODUCT_SUFFIX@ JDK_RC_PLATFORM_NAME:=@JDK_RC_PLATFORM_NAME@ COMPANY_NAME:=@COMPANY_NAME@ +HOTSPOT_VM_DISTRO:=@HOTSPOT_VM_DISTRO@ MACOSX_BUNDLE_NAME_BASE=@MACOSX_BUNDLE_NAME_BASE@ MACOSX_BUNDLE_ID_BASE=@MACOSX_BUNDLE_ID_BASE@ USERNAME:=@USERNAME@ @@ -201,11 +209,32 @@ RUNTIME_NAME=$(PRODUCT_NAME) $(PRODUCT_SUFFIX) # How to compile the code: release, fastdebug or slowdebug DEBUG_LEVEL:=@DEBUG_LEVEL@ +HOTSPOT_DEBUG_LEVEL:=@HOTSPOT_DEBUG_LEVEL@ # This is the JDK variant to build. # The JDK variant is a name for a specific set of modules to be compiled for the JDK. JDK_VARIANT:=@JDK_VARIANT@ +# Which JVM variants to build (space-separated list) +JVM_VARIANTS := @JVM_VARIANTS@ + +# Lists of features per variant. Only relevant for the variants listed in +# JVM_VARIANTS. +JVM_FEATURES_server := @JVM_FEATURES_server@ +JVM_FEATURES_client := @JVM_FEATURES_client@ +JVM_FEATURES_core := @JVM_FEATURES_core@ +JVM_FEATURES_minimal := @JVM_FEATURES_minimal@ +JVM_FEATURES_zero := @JVM_FEATURES_zero@ +JVM_FEATURES_zeroshark := @JVM_FEATURES_zeroshark@ +JVM_FEATURES_custom := @JVM_FEATURES_custom@ + +# Used for make-time verifications +VALID_JVM_FEATURES := @VALID_JVM_FEATURES@ +VALID_JVM_VARIANTS := @VALID_JVM_VARIANTS@ + +# Control use of precompiled header in hotspot libjvm build +USE_PRECOMPILED_HEADER := @USE_PRECOMPILED_HEADER@ + # Should we compile support for running with a graphical UI? (ie headful) # Should we compile support for running without? (ie headless) SUPPORT_HEADFUL:=@SUPPORT_HEADFUL@ @@ -213,25 +242,11 @@ SUPPORT_HEADLESS:=@SUPPORT_HEADLESS@ # Legacy defines controlled by the SUPPORT_HEADLESS and SUPPORT_HEADFUL options. @BUILD_HEADLESS@ -# These are the libjvms that we want to build. -# The java launcher uses the default. -# The others can be selected by specifying -client -server -minimal1 -zero or -zeroshark -# on the java launcher command line. -JVM_VARIANTS:=@JVM_VARIANTS@ -JVM_VARIANT_SERVER:=@JVM_VARIANT_SERVER@ -JVM_VARIANT_CLIENT:=@JVM_VARIANT_CLIENT@ -JVM_VARIANT_MINIMAL1:=@JVM_VARIANT_MINIMAL1@ -JVM_VARIANT_ZERO:=@JVM_VARIANT_ZERO@ -JVM_VARIANT_ZEROSHARK:=@JVM_VARIANT_ZEROSHARK@ -JVM_VARIANT_CORE:=@JVM_VARIANT_CORE@ +# Legacy support +USE_NEW_HOTSPOT_BUILD:=@USE_NEW_HOTSPOT_BUILD@ -# Universal binaries on macosx MACOSX_UNIVERSAL=@MACOSX_UNIVERSAL@ -# Legacy setting: -debug or -fastdebug -# Still used in version string... -BUILD_VARIANT_RELEASE:=@BUILD_VARIANT_RELEASE@ - # JDK_OUTPUTDIR specifies where a working jvm is built. # You can run $(JDK_OUTPUTDIR)/bin/java # Though the layout of the contents of $(JDK_OUTPUTDIR) is not @@ -318,6 +333,11 @@ MACOSX_VERSION_MIN=@MACOSX_VERSION_MIN@ # Toolchain type: gcc, clang, solstudio, lxc, microsoft... TOOLCHAIN_TYPE:=@TOOLCHAIN_TYPE@ TOOLCHAIN_VERSION := @TOOLCHAIN_VERSION@ +CC_VERSION_NUMBER := @CC_VERSION_NUMBER@ +CXX_VERSION_NUMBER := @CXX_VERSION_NUMBER@ + +# Legacy support +HOTSPOT_TOOLCHAIN_TYPE := @HOTSPOT_TOOLCHAIN_TYPE@ # Option used to tell the compiler whether to create 32- or 64-bit executables COMPILER_TARGET_BITS_FLAG:=@COMPILER_TARGET_BITS_FLAG@ @@ -336,14 +356,18 @@ LD_OUT_OPTION:=@LD_OUT_OPTION@ AR_OUT_OPTION:=@AR_OUT_OPTION@ # Flags used for overriding the default opt setting for a C/C++ source file. +C_O_FLAG_HIGHEST_JVM:=@C_O_FLAG_HIGHEST_JVM@ C_O_FLAG_HIGHEST:=@C_O_FLAG_HIGHEST@ C_O_FLAG_HI:=@C_O_FLAG_HI@ C_O_FLAG_NORM:=@C_O_FLAG_NORM@ C_O_FLAG_NONE:=@C_O_FLAG_NONE@ +C_O_FLAG_SIZE:=@C_O_FLAG_SIZE@ +CXX_O_FLAG_HIGHEST_JVM:=@CXX_O_FLAG_HIGHEST_JVM@ CXX_O_FLAG_HIGHEST:=@CXX_O_FLAG_HIGHEST@ CXX_O_FLAG_HI:=@CXX_O_FLAG_HI@ CXX_O_FLAG_NORM:=@CXX_O_FLAG_NORM@ CXX_O_FLAG_NONE:=@CXX_O_FLAG_NONE@ +CXX_O_FLAG_SIZE:=@CXX_O_FLAG_SIZE@ C_FLAG_DEPS:=@C_FLAG_DEPS@ CXX_FLAG_DEPS:=@CXX_FLAG_DEPS@ @@ -372,6 +396,23 @@ CXXFLAGS_JDKEXE:=@CXXFLAGS_JDKEXE@ LDFLAGS_HASH_STYLE := @LDFLAGS_HASH_STYLE@ +JVM_CFLAGS := @JVM_CFLAGS@ +JVM_CFLAGS_SYMBOLS := @JVM_CFLAGS_SYMBOLS@ +JVM_LDFLAGS := @JVM_LDFLAGS@ +JVM_ASFLAGS := @JVM_ASFLAGS@ +JVM_LIBS := @JVM_LIBS@ +JVM_RCFLAGS := @JVM_RCFLAGS@ + +# Flags for zeroshark +LLVM_CFLAGS := @LLVM_CFLAGS@ +LLVM_LIBS := @LLVM_LIBS@ +LLVM_LDFLAGS := @LLVM_LDFLAGS@ + +# These flags might contain variables set by a custom extension that is included later. +EXTRA_CFLAGS = @EXTRA_CFLAGS@ +EXTRA_CXXFLAGS = @EXTRA_CXXFLAGS@ +EXTRA_LDFLAGS = @EXTRA_LDFLAGS@ + CXX:=@FIXPATH@ @CCACHE@ @ICECC@ @CXX@ CPP:=@FIXPATH@ @CPP@ @@ -628,6 +669,7 @@ XATTR:=@XATTR@ JT_HOME:=@JT_HOME@ JTREGEXE:=@JTREGEXE@ XCODEBUILD=@XCODEBUILD@ +DTRACE := @DTRACE@ FIXPATH:=@FIXPATH@ # Build setup diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index 263c0a8ff2c..7e7a07c5d8b 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -930,6 +930,17 @@ AC_DEFUN_ONCE([TOOLCHAIN_MISC_CHECKS], rm -rf version-script.map main.c a.out fi AC_SUBST(USING_BROKEN_SUSE_LD) + + # Setup hotspot lecagy names for toolchains + HOTSPOT_TOOLCHAIN_TYPE=$TOOLCHAIN_TYPE + if test "x$TOOLCHAIN_TYPE" = xclang; then + HOTSPOT_TOOLCHAIN_TYPE=gcc + elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then + HOTSPOT_TOOLCHAIN_TYPE=sparcWorks + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + HOTSPOT_TOOLCHAIN_TYPE=visCPP + fi + AC_SUBST(HOTSPOT_TOOLCHAIN_TYPE) ]) # Setup the JTReg Regression Test Harness. diff --git a/common/autoconf/version-numbers b/common/autoconf/version-numbers index dcde2286a29..98f106680b5 100644 --- a/common/autoconf/version-numbers +++ b/common/autoconf/version-numbers @@ -32,6 +32,7 @@ PRODUCT_NAME=OpenJDK PRODUCT_SUFFIX="Runtime Environment" JDK_RC_PLATFORM_NAME=Platform COMPANY_NAME=N/A +HOTSPOT_VM_DISTRO="OpenJDK" # Might need better names for these MACOSX_BUNDLE_NAME_BASE="OpenJDK" diff --git a/common/bin/compare.sh b/common/bin/compare.sh index d073fbbda32..0447334042e 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -732,6 +732,13 @@ compare_bin_file() { SYM_SORT_CMD="cat" fi + if [ -n "$SYMBOLS_DIFF_FILTER" ] && [ -z "$NEED_SYMBOLS_DIFF_FILTER" ] \ + || [[ "$NEED_SYMBOLS_DIFF_FILTER" = *"$BIN_FILE"* ]]; then + this_SYMBOLS_DIFF_FILTER="$SYMBOLS_DIFF_FILTER" + else + this_SYMBOLS_DIFF_FILTER="$CAT" + fi + # Check symbols if [ "$OPENJDK_TARGET_OS" = "windows" ]; then # The output from dumpbin on windows differs depending on if the debug symbol @@ -750,8 +757,16 @@ compare_bin_file() { $NM -j $ORIG_OTHER_FILE 2> /dev/null | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other $NM -j $ORIG_THIS_FILE 2> /dev/null | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this else - $NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other - $NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this + $NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME \ + | $AWK '{print $2, $3, $4, $5}' \ + | eval "$this_SYMBOLS_DIFF_FILTER" \ + | $SYM_SORT_CMD \ + > $WORK_FILE_BASE.symbols.other + $NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME \ + | $AWK '{print $2, $3, $4, $5}' \ + | eval "$this_SYMBOLS_DIFF_FILTER" \ + | $SYM_SORT_CMD \ + > $WORK_FILE_BASE.symbols.this fi LC_ALL=C $DIFF $WORK_FILE_BASE.symbols.other $WORK_FILE_BASE.symbols.this > $WORK_FILE_BASE.symbols.diff @@ -828,9 +843,10 @@ compare_bin_file() { FULLDUMP_DIFF_FILTER="$CAT" fi $FULLDUMP_CMD $OTHER_FILE | eval "$BUILD_ID_FILTER" | eval "$FULLDUMP_DIFF_FILTER" \ - > $WORK_FILE_BASE.fulldump.other 2>&1 + > $WORK_FILE_BASE.fulldump.other 2>&1 & $FULLDUMP_CMD $THIS_FILE | eval "$BUILD_ID_FILTER" | eval "$FULLDUMP_DIFF_FILTER" \ - > $WORK_FILE_BASE.fulldump.this 2>&1 + > $WORK_FILE_BASE.fulldump.this 2>&1 & + wait LC_ALL=C $DIFF $WORK_FILE_BASE.fulldump.other $WORK_FILE_BASE.fulldump.this \ > $WORK_FILE_BASE.fulldump.diff @@ -854,18 +870,19 @@ compare_bin_file() { FULLDUMP_MSG=" " DIFF_FULLDUMP= if [[ "$KNOWN_FULLDUMP_DIFF $ACCEPTED_FULLDUMP_DIFF" = *"$BIN_FILE"* ]]; then - FULLDUMP_MSG=" ! " + FULLDUMP_MSG=" ! " fi fi fi # Compare disassemble output if [ -n "$DIS_CMD" ] && [ -z "$SKIP_DIS_DIFF" ]; then - # By default we filter out differences that include references to symbols. - # To get a raw diff with the complete disassembly, set - # DIS_DIFF_FILTER="$CAT" - if [ -z "$DIS_DIFF_FILTER" ]; then - DIS_DIFF_FILTER="$GREP -v ' # .* <.*>$' | $SED -r -e 's/(\b|x)([0-9a-fA-F]+)(\b|:|>)/X/g'" + this_DIS_DIFF_FILTER="$CAT" + if [ -n "$DIS_DIFF_FILTER" ]; then + if [ -z "$NEED_DIS_DIFF_FILTER" ] \ + || [[ "$NEED_DIS_DIFF_FILTER" = *"$BIN_FILE"* ]]; then + this_DIS_DIFF_FILTER="$DIS_DIFF_FILTER" + fi fi if [ "$OPENJDK_TARGET_OS" = "windows" ]; then DIS_GREP_ARG=-a @@ -873,9 +890,10 @@ compare_bin_file() { DIS_GREP_ARG= fi $DIS_CMD $OTHER_FILE | $GREP $DIS_GREP_ARG -v $NAME \ - | eval "$DIS_DIFF_FILTER" > $WORK_FILE_BASE.dis.other 2>&1 + | eval "$this_DIS_DIFF_FILTER" > $WORK_FILE_BASE.dis.other 2>&1 & $DIS_CMD $THIS_FILE | $GREP $DIS_GREP_ARG -v $NAME \ - | eval "$DIS_DIFF_FILTER" > $WORK_FILE_BASE.dis.this 2>&1 + | eval "$this_DIS_DIFF_FILTER" > $WORK_FILE_BASE.dis.this 2>&1 & + wait LC_ALL=C $DIFF $WORK_FILE_BASE.dis.other $WORK_FILE_BASE.dis.this > $WORK_FILE_BASE.dis.diff @@ -884,11 +902,15 @@ compare_bin_file() { DIS_MSG=$($PRINTF "%8d" $DIS_DIFF_SIZE) if [[ "$ACCEPTED_DIS_DIFF" != *"$BIN_FILE"* ]]; then DIFF_DIS=true - if [[ "$KNOWN_DIS_DIFF" != *"$BIN_FILE"* ]]; then + if [ "$MAX_KNOWN_DIS_DIFF_SIZE" = "" ]; then + MAX_KNOWN_DIS_DIFF_SIZE="0" + fi + if [[ "$KNOWN_DIS_DIFF" = *"$BIN_FILE"* ]] \ + && [ "$DIS_DIFF_SIZE" -lt "$MAX_KNOWN_DIS_DIFF_SIZE" ]; then + DIS_MSG=" $DIS_MSG " + else DIS_MSG="*$DIS_MSG*" REGRESSIONS=true - else - DIS_MSG=" $DIS_MSG " fi else DIS_MSG="($DIS_MSG)" diff --git a/common/bin/compare_exceptions.sh.incl b/common/bin/compare_exceptions.sh.incl index 30ae49c6fc1..9a6f85fb734 100644 --- a/common/bin/compare_exceptions.sh.incl +++ b/common/bin/compare_exceptions.sh.incl @@ -113,21 +113,36 @@ if [ "$OPENJDK_TARGET_OS" = "linux" ]; then ./bin/xjc " - # Issue with __FILE__ usage in generated header files prevent clean fulldump diff of - # server jvm with old hotspot build. - KNOWN_FULLDUMP_DIFF=" - ./lib$OPENJDK_TARGET_CPU_LIBDIR/client/libjvm.so - ./lib$OPENJDK_TARGET_CPU_LIBDIR/server/libjvm.so - ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so - " - - if [ "$OPENJDK_TARGET_CPU" = "x86" ]; then - KNOWN_DIS_DIFF=" - ./lib$OPENJDK_TARGET_CPU_LIBDIR/server/libjvm.so + if [ "$OPENJDK_TARGET_CPU" = "arm" ]; then + # NOTE: When comparing the old and new hotspot builds, the link time + # optimization makes good comparisons impossible. Fulldump compare always + # fails and disassembly can end up with some functions in different order. + # So for now, accept the difference but put a limit on the size. The + # different order of functions shouldn't result in a very big diff. + KNOWN_FULLDUMP_DIFF=" + ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so + " + + # Link time optimization adds random numbers to symbol names + NEED_DIS_DIFF_FILTER=" + ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so + " + DIS_DIFF_FILTER="$SED -r \ + -e 's/\.[0-9]+/.X/g' \ + -e 's/\t[0-9a-f]{4} [0-9a-f]{4} /\tXXXX XXXX /' \ + -e 's/\t[0-9a-f]{5,} /\t /' \ + " + KNOWN_DIS_DIFF=" + ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so + " + MAX_KNOWN_DIS_DIFF_SIZE="3000" + + NEED_SYMBOLS_DIFF_FILTER=" + ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so + " + SYMBOLS_DIFF_FILTER="$SED -r \ + -e 's/\.[0-9]+/.X/g' " - DIS_DIFF_FILTER="$SED \ - -e 's/\(:\t\)\([0-9a-z]\{2,2\} \)\{1,7\}/\1/g' \ - -e 's/0x[0-9a-z]\{2,9\}//g'" fi fi @@ -250,15 +265,10 @@ if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; SKIP_FULLDUMP_DIFF="true" - # Filter random C++ symbol strings. - # Some numbers differ randomly. + # Random strings looking like this differ: <.XAKoKoPIac2W0OA. DIS_DIFF_FILTER="$SED \ - -e 's/\.[a-zA-Z0-9_\$]\{15\}//g' \ - -e 's/\(\# \)[0-9a-f]*\( <\)/\1\2/g' \ - -e 's/0x[0-9a-f]*$//g' \ - -e 's/0x[0-9a-f]*\([,(>]\)/\1/g' \ - -e 's/: [0-9a-f][0-9a-f]\( [0-9a-f][0-9a-f]\)\{2,10\}/: /g' \ - -e 's/ [\.A-Za-z0-9%@]\{16\}$/ /g'" + -e 's/<\.[A-Za-z0-9]\{\15}\./<.SYM./' \ + " fi @@ -380,23 +390,18 @@ if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "sparcv9" ] ./bin/xjc " - # Some numbers differ randomly. DIS_DIFF_FILTER="$SED \ - -e 's/\$[a-zA-Z0-9_\$]\{15\}//g' \ - -e 's/: [0-9a-f][0-9a-f]\( [0-9a-f][0-9a-f]\)\{2,10\}/: /g' \ - -e 's/, [0-9a-fx\-]\{1,8\}/, /g' \ - -e 's/call [0-9a-f]\{7\}/call /g' \ + -e 's/^[0-9a-f]\{16\}/:/' \ + -e 's/^ *[0-9a-f]\{3,8\}:/ :/' \ + -e 's/: [0-9a-f][0-9a-f]\( [0-9a-f][0-9a-f]\)\{2,10\}/: /' \ + -e 's/\$[a-zA-Z0-9_\$]\{15\}\././' \ -e 's/0x[0-9a-f]\{1,8\}//g' \ - -e 's/\! [0-9a-f]\{1,8\} /! /g'" + -e 's/\! [0-9a-f]\{1,8\} /! /' \ + -e 's/, [0-9a-fx\-]\{1,8\}/, /g' \ + -e 's/call [0-9a-f]\{4,7\}/call /' \ + " - # libjvm.so - # __FILE__ macro usage in debug.hpp causes differences between old and new - # hotspot builds in ad_sparc.o and ad_sparc_clone.o. The .o files compare - # equal when stripped, but at link time differences appear. Removing - # __FILE__ from ShouldNotCallThis() and ShouldNotReachHere() removes - # the differences. KNOWN_DIS_DIFF=" - ./lib/sparcv9/server/libjvm.so ./lib/sparcv9/libsaproc.so " @@ -419,6 +424,7 @@ if [ "$OPENJDK_TARGET_OS" = "windows" ]; then ./demo/jvmti/minst/lib/minst.dll ./bin/attach.dll ./bin/jsoundds.dll + ./bin/client/jvm.dll ./bin/server/jvm.dll ./bin/appletviewer.exe ./bin/idlj.exe @@ -469,22 +475,39 @@ if [ "$OPENJDK_TARGET_OS" = "windows" ]; then ./bin/jabswitch.exe " - # On windows, there are unavoidable allignment issues making - # a perfect disasm diff impossible. Filter out the following: - # * Random parts of C++ symbols (this is a bit greedy, but does the trick) - # @XXXXX - # * Hexadecimal addresses that are sometimes alligned differently. - # * Dates in version strings XXXX_XX_XX. - DIS_DIFF_FILTER="$SED \ - -e 's/^ [0-9A-F]\{16\}: //g' \ - -e 's/[@?][A-Za-z0-9_]\{1,25\}//g' \ - -e 's/\([\[+]\)[0-9A-F]\{4,16\}h\]/\1]/g' \ - -e 's/_[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}/_/g'" - #DIS_DIFF_FILTER="$CAT" + if [ "$OPENJDK_TARGET_CPU" = "x86" ]; then + DIS_DIFF_FILTER="$SED -r \ + -e 's/^ [0-9A-F]{16}: //' \ + -e 's/^ [0-9A-F]{8}: / : /' \ + -e 's/(offset \?\?)_C@_.*/\1/' \ + -e 's/[@?][A-Za-z0-9_]{1,25}//' \ + -e 's/([-,+])[0-9A-F]{2,16}/\1/g' \ + -e 's/\[[0-9A-F]{4,16}h\]/[]/' \ + -e 's/: ([a-z]{2}[a-z ]{2}) [0-9A-F]{2,16}h?$/: \1 /' \ + -e 's/_20[0-9]{2}_[0-1][0-9]_[0-9]{2}/_/' \ + " + elif [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; then + DIS_DIFF_FILTER="$SED -r \ + -e 's/^ [0-9A-F]{16}: //' \ + -e 's/\[[0-9A-F]{4,16}h\]/[]/' \ + -e 's/([,+])[0-9A-F]{2,16}h/\1/' \ + -e 's/([a-z]{2}[a-z ]{2}) [0-9A-F]{4,16}$/\1 /' \ + -e 's/\[\?\?_C@_.*/[]/' \ + " + fi SKIP_BIN_DIFF="true" SKIP_FULLDUMP_DIFF="true" + # NOTE: When comparing the old and new hotspot builds, the server jvm.dll + # cannot be made equal in disassembly. Some functions just always end up + # in different order. So for now, accept the difference but put a limit + # on the size. The different order of functions shouldn't result in a very + # big diff. + KNOWN_DIS_DIFF=" + ./bin/server/jvm.dll + " + MAX_KNOWN_DIS_DIFF_SIZE="2000000" fi @@ -565,6 +588,7 @@ if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then ./Contents/Home/lib/libverify.dylib ./Contents/Home/lib/libsaproc.dylib ./Contents/Home/lib/libsplashscreen.dylib + ./Contents/Home/lib/server/libjsig.dylib ./Contents/Home/lib/server/libjvm.dylib ./Contents/Home/lib/deploy/JavaControlPanel.prefPane/Contents/MacOS/JavaControlPanel ./Contents/Resources/JavaControlPanelHelper @@ -590,6 +614,7 @@ if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then ./lib/libverify.dylib ./lib/libsaproc.dylib ./lib/libsplashscreen.dylib + ./lib/server/libjsig.dylib ./lib/server/libjvm.dylib ./lib/deploy/JavaControlPanel.prefPane/Contents/MacOS/JavaControlPanel ./Versions/A/Resources/finish_installation.app/Contents/MacOS/finish_installation @@ -606,7 +631,8 @@ if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then DIS_DIFF_FILTER="LANG=C $SED \ -e 's/0x[0-9a-f]\{3,16\}//g' -e 's/^[0-9a-f]\{12,20\}//' \ - -e 's/## literal pool for: .Java HotSpot(TM) 64-Bit Server VM.*//g' + -e 's/-20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]-[0-2][0-9]\{5\}//g' \ + -e 's/), built on .*/), /' \ " fi diff --git a/common/conf/jib-profiles.js b/common/conf/jib-profiles.js index a3372cf3fe2..123c6be1f29 100644 --- a/common/conf/jib-profiles.js +++ b/common/conf/jib-profiles.js @@ -241,7 +241,7 @@ var getJibProfilesProfiles = function (input, common) { target_os: "linux", target_cpu: "x64", dependencies: concat(common.dependencies, "devkit"), - configure_args: concat(common.configure_args, "--with-zlib=system"), + configure_args: concat(common.configure_args, "--with-zlib=system"), make_args: common.make_args }, @@ -259,7 +259,7 @@ var getJibProfilesProfiles = function (input, common) { target_os: "macosx", target_cpu: "x64", dependencies: concat(common.dependencies, "devkit"), - configure_args: concat(common.configure_args, "--with-zlib=system"), + configure_args: concat(common.configure_args, "--with-zlib=system"), make_args: common.make_args }, @@ -267,7 +267,7 @@ var getJibProfilesProfiles = function (input, common) { target_os: "solaris", target_cpu: "x64", dependencies: concat(common.dependencies, "devkit", "cups"), - configure_args: concat(common.configure_args, "--with-zlib=system"), + configure_args: concat(common.configure_args, "--with-zlib=system"), make_args: common.make_args }, @@ -275,7 +275,7 @@ var getJibProfilesProfiles = function (input, common) { target_os: "solaris", target_cpu: "sparcv9", dependencies: concat(common.dependencies, "devkit", "cups"), - configure_args: concat(common.configure_args, "--with-zlib=system"), + configure_args: concat(common.configure_args, "--with-zlib=system"), make_args: common.make_args }, diff --git a/make/Jprt.gmk b/make/Jprt.gmk index 6b778293d2a..e7eba24bd31 100644 --- a/make/Jprt.gmk +++ b/make/Jprt.gmk @@ -108,7 +108,9 @@ SRC_JDK_MACOSX_BUNDLE_DIR := $(JDK_MACOSX_BUNDLE_DIR) SRC_JRE_MACOSX_BUNDLE_DIR := $(JRE_MACOSX_BUNDLE_DIR) # Bundle up the images -bundles: all +JPRT_TARGET ?= all +ifeq ($(JPRT_TARGET), all) + bundles: $(JPRT_TARGET) @$(call TargetEnter) $(MKDIR) -p $(BUILD_OUTPUT)/bundles $(CD) $(SRC_JDK_IMAGE_DIR) && $(ZIP) -y -q -r \ @@ -128,9 +130,24 @@ bundles: all $(BUILD_OUTPUT)/bundles/$(SYMBOLS_IMAGE_SUBDIR).zip . ; \ fi @$(call TargetExit) +else + # Just fake the bundles + bundles: $(JPRT_TARGET) + @$(call TargetEnter) + $(MKDIR) -p $(BUILD_OUTPUT)/bundles + $(CD) $(TOPDIR) && $(ZIP) -y -q -r \ + $(BUILD_OUTPUT)/bundles/$(JDK_IMAGE_SUBDIR).zip README + $(CD) $(TOPDIR) && $(ZIP) -y -q -r \ + $(BUILD_OUTPUT)/bundles/$(JRE_IMAGE_SUBDIR).zip README + $(CD) $(TOPDIR) && $(ZIP) -y -q -r \ + $(BUILD_OUTPUT)/bundles/$(TEST_IMAGE_SUBDIR).zip README + $(CD) $(TOPDIR) && $(ZIP) -y -q -r \ + $(BUILD_OUTPUT)/bundles/modules.zip README + @$(call TargetExit) +endif # Copy images to one unified location regardless of platform etc. -final-images: all +final-images: $(JPRT_TARGET) @$(call TargetEnter) $(RM) -r $(BUILD_OUTPUT)/final-images $(MKDIR) -p $(BUILD_OUTPUT)/final-images/$(JDK_IMAGE_SUBDIR) diff --git a/make/Main.gmk b/make/Main.gmk index 5d8137f2b47..6f77baa92eb 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -229,10 +229,17 @@ ALL_TARGETS += $(LAUNCHER_TARGETS) ifeq ($(BUILD_HOTSPOT),true) hotspot: - +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f HotspotWrapper.gmk) + ifeq ($(USE_NEW_HOTSPOT_BUILD), true) + +($(CD) $(HOTSPOT_TOPDIR)/makefiles && $(MAKE) $(MAKE_ARGS) -f BuildHotspot.gmk) + else + +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f HotspotWrapper.gmk) + endif endif -ALL_TARGETS += hotspot +hotspot-ide-project: + +($(CD) $(HOTSPOT_TOPDIR)/makefiles && $(MAKE) $(MAKE_ARGS) -f ide/CreateVSProject.gmk) + +ALL_TARGETS += hotspot hotspot-ide-project ################################################################################ # Build demos and samples targets @@ -462,6 +469,8 @@ else $(JAVA_TARGETS): interim-langtools + hotspot-ide-project: hotspot exploded-image + import-hotspot: hotspot generate-exported-symbols: java.base-libs jdk.jdwp.agent-libs diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index 7ed52135f28..dd9de199f37 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -730,6 +730,16 @@ endif PathList = \ "$(subst $(SPACE),$(PATH_SEP),$(strip $1))" +################################################################################ +# Check if a specified hotspot variant is being built, or at least one of a +# list of variants. Will return 'true' or 'false'. +# $1 - the variant to test for +check-jvm-variant = \ + $(strip \ + $(if $(filter-out $(VALID_JVM_VARIANTS), $1), \ + $(error Internal error: Invalid variant tested: $1)) \ + $(if $(filter $1, $(JVM_VARIANTS)), true, false)) + ################################################################################ # Hook to include the corresponding custom file, if present. diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index d6a003a8c8e..d595e044013 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -197,14 +197,51 @@ define add_native_source $1_$2_THIS_FILE = -DTHIS_FILE='"$$( Disable the given warnings for the specified toolchain # DISABLED_WARNINGS_C_ Disable the given warnings for the specified toolchain # when compiling C code @@ -331,7 +372,11 @@ endef # toolchain when compiling C++ code # STRIP_SYMBOLS Set to true to strip the final binary if the toolchain allows for it # DEBUG_SYMBOLS Set to false to disable generation of debug symbols +# CFLAGS_DEBUG_SYMBOLS Overrides the default cflags for enabling debug symbols +# CXXFLAGS_DEBUG_SYMBOLS Overrides the default cxxflags for enabling debug symbols # STRIPFLAGS Optionally change the flags given to the strip command +# PRECOMPILED_HEADER Header file to use as precompiled header +# PRECOMPILED_HEADER_EXCLUDE List of source files that should not use PCH SetupNativeCompilation = $(NamedParamsMacroTemplate) define SetupNativeCompilationBody @@ -556,8 +601,10 @@ define SetupNativeCompilationBody endif ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true) - $1_EXTRA_CFLAGS += $(CFLAGS_DEBUG_SYMBOLS) - $1_EXTRA_CXXFLAGS += $(CXXFLAGS_DEBUG_SYMBOLS) + $$(call SetIfEmpty, $1_CFLAGS_DEBUG_SYMBOLS, $(CFLAGS_DEBUG_SYMBOLS)) + $$(call SetIfEmpty, $1_CXXFLAGS_DEBUG_SYMBOLS, $(CXXFLAGS_DEBUG_SYMBOLS)) + $1_EXTRA_CFLAGS += $$($1_CFLAGS_DEBUG_SYMBOLS) + $1_EXTRA_CXXFLAGS += $$($1_CXXFLAGS_DEBUG_SYMBOLS) endif ifneq (,$$($1_REORDER)) @@ -597,17 +644,23 @@ define SetupNativeCompilationBody endif ifeq (NONE, $$($1_OPTIMIZATION)) - $1_EXTRA_CFLAGS += $(C_O_FLAG_NONE) - $1_EXTRA_CXXFLAGS += $(CXX_O_FLAG_NONE) + $1_OPT_CFLAGS := $(C_O_FLAG_NONE) + $1_OPT_CXXFLAGS := $(CXX_O_FLAG_NONE) else ifeq (LOW, $$($1_OPTIMIZATION)) - $1_EXTRA_CFLAGS += $(C_O_FLAG_NORM) - $1_EXTRA_CXXFLAGS += $(CXX_O_FLAG_NORM) + $1_OPT_CFLAGS := $(C_O_FLAG_NORM) + $1_OPT_CXXFLAGS := $(CXX_O_FLAG_NORM) else ifeq (HIGH, $$($1_OPTIMIZATION)) - $1_EXTRA_CFLAGS += $(C_O_FLAG_HI) - $1_EXTRA_CXXFLAGS += $(CXX_O_FLAG_HI) + $1_OPT_CFLAGS := $(C_O_FLAG_HI) + $1_OPT_CXXFLAGS := $(CXX_O_FLAG_HI) else ifeq (HIGHEST, $$($1_OPTIMIZATION)) - $1_EXTRA_CFLAGS += $(C_O_FLAG_HIGHEST) - $1_EXTRA_CXXFLAGS += $(CXX_O_FLAG_HIGHEST) + $1_OPT_CFLAGS := $(C_O_FLAG_HIGHEST) + $1_OPT_CXXFLAGS := $(CXX_O_FLAG_HIGHEST) + else ifeq (HIGHEST_JVM, $$($1_OPTIMIZATION)) + $1_OPT_CFLAGS := $(C_O_FLAG_HIGHEST_JVM) + $1_OPT_CXXFLAGS := $(CXX_O_FLAG_HIGHEST_JVM) + else ifeq (SIZE, $$($1_OPTIMIZATION)) + $1_OPT_CFLAGS := $(C_O_FLAG_SIZE) + $1_OPT_CXXFLAGS := $(CXX_O_FLAG_SIZE) else ifneq (, $$($1_OPTIMIZATION)) $$(error Unknown value for OPTIMIZATION: $$($1_OPTIMIZATION)) endif @@ -618,11 +671,65 @@ define SetupNativeCompilationBody # lines for all object files in this setup. This includes at least all the # variables used in the call to add_native_source below. $1_COMPILE_VARDEPS := $$($1_CFLAGS) $$($1_EXTRA_CFLAGS) $$($1_SYSROOT_CFLAGS) \ - $$($1_CXXFLAGS) $$($1_EXTRA_CXXFLAGS) \ + $$($1_CXXFLAGS) $$($1_EXTRA_CXXFLAGS) $$($1_OPT_CFLAGS) $$($1_OPT_CXXFLAGS) \ $$($1_CC) $$($1_CXX) $$($1_AS) $$($1_ASFLAGS) $1_COMPILE_VARDEPS_FILE := $$(call DependOnVariable, $1_COMPILE_VARDEPS, \ $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).comp.vardeps) + ifneq ($$($1_PRECOMPILED_HEADER), ) + ifeq ($(USE_PRECOMPILED_HEADER), 1) + ifeq ($(TOOLCHAIN_TYPE), microsoft) + $1_PCH_FILE := $$($1_OBJECT_DIR)/$1.pch + $1_GENERATED_PCH_SRC := $$($1_OBJECT_DIR)/$1_pch.cpp + $1_GENERATED_PCH_OBJ := $$($1_OBJECT_DIR)/$1_pch.obj + + $$(eval $$(call add_native_source,$1,$$($1_GENERATED_PCH_SRC), \ + $$($1_OBJECT_DIR),,, \ + $$($1_CXXFLAGS) $$($1_EXTRA_CXXFLAGS) $$($1_SYSROOT_CFLAGS) \ + -Fp$$($1_PCH_FILE) -Yc$$(notdir $$($1_PRECOMPILED_HEADER)), \ + $$($1_CXX),,no_this_file)) + + $1_USE_PCH_FLAGS := \ + -Fp$$($1_PCH_FILE) -Yu$$(notdir $$($1_PRECOMPILED_HEADER)) + + $$($1_ALL_OBJS): $$($1_GENERATED_PCH_OBJ) + + # Explicitly add the pch obj file first to ease comparing to old + # hotspot build. + $1_ALL_OBJS := $$($1_GENERATED_PCH_OBJ) $$($1_ALL_OBJS) + + $$($1_GENERATED_PCH_SRC): + $(ECHO) "#include \"$$(notdir $$($1_PRECOMPILED_HEADER))\"" > $$@ + + else ifneq ($(findstring $(TOOLCHAIN_TYPE), gcc clang), ) + ifeq ($(TOOLCHAIN_TYPE), gcc) + $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).gch + $1_USE_PCH_FLAGS := -I$$($1_OBJECT_DIR)/precompiled + else ifeq ($(TOOLCHAIN_TYPE), clang) + $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).pch + $1_USE_PCH_FLAGS := -include-pch $$($1_PCH_FILE) + endif + $1_PCH_DEP := $$($1_PCH_FILE).d + $1_PCH_DEP_TARGETS := $$($1_PCH_FILE).d.targets + + -include $$($1_PCH_DEP) + -include $$($1_PCH_DEP_TARGETS) + + $$($1_PCH_FILE): $$($1_PRECOMPILED_HEADER) $$($1_COMPILE_VARDEPS_FILE) + $$(call LogInfo, Generating precompiled header) + $$(call MakeDir, $$(@D)) + $$(call ExecuteWithLog, $$@, \ + $$($1_CC) $$($1_CFLAGS) $$($1_EXTRA_CFLAGS) $$($1_SYSROOT_CFLAGS) \ + $$($1_OPT_CFLAGS) \ + -x c++-header -c $(C_FLAG_DEPS) $$($1_PCH_DEP) $$< -o $$@) + $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_PCH_DEP) > $$($1_PCH_DEP_TARGETS) + + $$($1_ALL_OBJS): $$($1_PCH_FILE) + + endif + endif + endif + # Now call add_native_source for each source file we are going to compile. $$(foreach p,$$($1_SRCS), \ $$(eval $$(call add_native_source,$1,$$p,$$($1_OBJECT_DIR), \ diff --git a/make/jprt.properties b/make/jprt.properties index 943f15b5be5..40a75b1140f 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -129,9 +129,15 @@ jprt.build.flavor.optimized.target=jprt_bundle jprt.build.flavor.optimizedOpen.target=jprt_bundle jprt.build.flavor.slowdebug.target=jprt_bundle -# Use these configure args to define debug level +# Use these configure args to define debug level or provide specific +# configuration details not covered by Jib profiles. jprt.slowdebug.build.configure.args= jprt.fastdebug.build.configure.args=--disable-precompiled-headers +# Don't disable precompiled headers on windows. It's simply too slow. +jprt.windows_i586.fastdebug.build.configure.args= +jprt.windows_x64.fastdebug.build.configure.args= +jprt.windows_i586.fastdebugOpen.build.configure.args= +jprt.windows_x64.fastdebugOpen.build.configure.args= jprt.product.build.configure.args= jprt.optimized.build.configure.args=--with-debug-level=optimized jprt.slowdebugOpen.build.configure.args=${jprt.slowdebug.build.configure.args} From 74f12569ece839f772463d081d8ba954962a1af9 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Fri, 8 Apr 2016 12:26:47 -0700 Subject: [PATCH 066/222] 8153123: Streamline StackWalker code Reviewed-by: coleenp, dfuchs, mchung, redestad --- jdk/make/mapfiles/libjava/mapfile-vers | 3 +- .../classes/java/lang/StackFrameInfo.java | 92 +-- .../classes/java/lang/StackStreamFactory.java | 765 ++++++++---------- .../share/classes/java/lang/Thread.java | 5 +- .../share/classes/java/lang/Throwable.java | 18 +- .../classes/java/lang/invoke/MemberName.java | 4 + .../internal/misc/JavaLangInvokeAccess.java | 5 + jdk/src/java.base/share/native/include/jvm.h | 11 +- .../share/native/libjava/StackFrameInfo.c | 22 +- .../share/native/libjava/StackStreamFactory.c | 13 +- .../java/lang/StackWalker/DumpStackTest.java | 3 - .../lang/StackWalker/GetCallerClassTest.java | 3 +- .../java/lang/StackWalker/StackWalkTest.java | 4 - .../lang/StackWalker/VerifyStackTrace.java | 3 +- 14 files changed, 391 insertions(+), 560 deletions(-) diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index eb35a623fb2..24db66e8e29 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -139,8 +139,7 @@ SUNWprivate_1.1 { Java_java_lang_Double_doubleToRawLongBits; Java_java_lang_Float_intBitsToFloat; Java_java_lang_Float_floatToRawIntBits; - Java_java_lang_StackFrameInfo_fillInStackFrames; - Java_java_lang_StackFrameInfo_setMethodInfo; + Java_java_lang_StackFrameInfo_toStackTraceElement0; Java_java_lang_StackStreamFactory_checkStackWalkModes; Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk; Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames; diff --git a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java index 0750af15b03..187a737d7c4 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java +++ b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java @@ -37,24 +37,14 @@ class StackFrameInfo implements StackFrame { private final static JavaLangInvokeAccess jlInvokeAccess = SharedSecrets.getJavaLangInvokeAccess(); - // -XX:+MemberNameInStackFrame will initialize MemberName and all other fields; - // otherwise, VM will set the hidden fields (injected by the VM). - // -XX:+MemberNameInStackFrame is temporary to enable performance measurement - // - // Footprint improvement: MemberName::clazz and MemberName::name - // can replace StackFrameInfo::declaringClass and StackFrameInfo::methodName - // Currently VM sets StackFrameInfo::methodName instead of expanding MemberName::name + // Footprint improvement: MemberName::clazz can replace + // StackFrameInfo::declaringClass. final StackWalker walker; final Class declaringClass; final Object memberName; - final int bci; - - // methodName, fileName, and lineNumber will be lazily set by the VM - // when first requested. - private String methodName; - private String fileName = null; // default for unavailable filename - private int lineNumber = -1; // default for unavailable lineNumber + final short bci; + private volatile StackTraceElement ste; /* * Create StackFrameInfo for StackFrameTraverser and LiveStackFrameTraverser @@ -78,77 +68,53 @@ class StackFrameInfo implements StackFrame { return declaringClass; } - // Call the VM to set methodName, lineNumber, and fileName - private synchronized void ensureMethodInfoInitialized() { - if (methodName == null) { - setMethodInfo(); - } - } - @Override public String getMethodName() { - ensureMethodInfoInitialized(); - return methodName; + return jlInvokeAccess.getName(memberName); } @Override - public Optional getFileName() { - ensureMethodInfoInitialized(); - return fileName != null ? Optional.of(fileName) : Optional.empty(); + public final Optional getFileName() { + StackTraceElement ste = toStackTraceElement(); + return ste.getFileName() != null ? Optional.of(ste.getFileName()) : Optional.empty(); } @Override - public OptionalInt getLineNumber() { - ensureMethodInfoInitialized(); - return lineNumber > 0 ? OptionalInt.of(lineNumber) : OptionalInt.empty(); + public final OptionalInt getLineNumber() { + StackTraceElement ste = toStackTraceElement(); + return ste.getLineNumber() > 0 ? OptionalInt.of(ste.getLineNumber()) : OptionalInt.empty(); } @Override - public boolean isNativeMethod() { - ensureMethodInfoInitialized(); - return lineNumber == -2; + public final boolean isNativeMethod() { + StackTraceElement ste = toStackTraceElement(); + return ste.isNativeMethod(); } @Override public String toString() { - ensureMethodInfoInitialized(); - // similar format as StackTraceElement::toString - if (isNativeMethod()) { - return getClassName() + "." + getMethodName() + "(Native Method)"; - } else { - // avoid allocating Optional objects - return getClassName() + "." + getMethodName() + - "(" + (fileName != null ? fileName : "Unknown Source") + - (lineNumber > 0 ? ":" + lineNumber : " bci:" + bci) + ")"; - } + StackTraceElement ste = toStackTraceElement(); + return ste.toString(); } /** - * Lazily initialize method name, file name, line number + * Fill in the fields of the given StackTraceElement */ - private native void setMethodInfo(); - - /** - * Fill in source file name and line number of the given StackFrame array. - */ - static native void fillInStackFrames(int startIndex, - Object[] stackframes, - int fromIndex, int toIndex); + private native void toStackTraceElement0(StackTraceElement ste); @Override public StackTraceElement toStackTraceElement() { - ensureMethodInfoInitialized(); - - Module module = declaringClass.getModule(); - String moduleName = module.isNamed() ? module.getName() : null; - String moduleVersion = null; - if (module.isNamed() && module.getDescriptor().version().isPresent()) { - moduleVersion = module.getDescriptor().version().get().toString(); + StackTraceElement s = ste; + if (s == null) { + synchronized (this) { + s = ste; + if (s == null) { + s = new StackTraceElement(); + toStackTraceElement0(s); + ste = s; + } + } } - return new StackTraceElement(moduleName, moduleVersion, - getClassName(), getMethodName(), - fileName, - lineNumber); + return s; } - } diff --git a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java index dcb471c4cc2..ac2e8916bea 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -24,9 +24,6 @@ */ package java.lang; -import jdk.internal.misc.VM; - -import java.io.PrintStream; import java.lang.StackWalker.Option; import java.lang.StackWalker.StackFrame; @@ -34,12 +31,9 @@ import java.lang.annotation.Native; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Arrays; -import java.util.EnumSet; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.Spliterator; import java.util.function.Consumer; @@ -60,8 +54,7 @@ import static java.lang.StackStreamFactory.WalkerState.*; * to avoid overhead of Stream/Lambda * 1. Support traversing Stream * 2. StackWalker::getCallerClass - * 3. Throwable::init and Throwable::getStackTrace - * 4. AccessControlContext getting ProtectionDomain + * 3. AccessControlContext getting ProtectionDomain */ final class StackStreamFactory { private StackStreamFactory() {} @@ -78,25 +71,22 @@ final class StackStreamFactory { // These flags must match the values maintained in the VM @Native private static final int DEFAULT_MODE = 0x0; @Native private static final int FILL_CLASS_REFS_ONLY = 0x2; - @Native private static final int FILTER_FILL_IN_STACKTRACE = 0x10; @Native private static final int SHOW_HIDDEN_FRAMES = 0x20; // LambdaForms are hidden by the VM @Native private static final int FILL_LIVE_STACK_FRAMES = 0x100; - /* * For Throwable to use StackWalker, set useNewThrowable to true. * Performance work and extensive testing is needed to replace the * VM built-in backtrace filled in Throwable with the StackWalker. */ - final static boolean useNewThrowable = getProperty("stackwalk.newThrowable", false); final static boolean isDebug = getProperty("stackwalk.debug", false); static StackFrameTraverser makeStackTraverser(StackWalker walker, Function, ? extends T> function) { if (walker.hasLocalsOperandsOption()) - return new LiveStackInfoTraverser(walker, function); + return new LiveStackInfoTraverser<>(walker, function); else - return new StackFrameTraverser(walker, function); + return new StackFrameTraverser<>(walker, function); } /** @@ -106,40 +96,31 @@ final class StackStreamFactory { return new CallerClassFinder(walker); } - static boolean useStackTrace(Throwable t) { - if (t instanceof VirtualMachineError) - return false; - - return VM.isBooted() && StackStreamFactory.useNewThrowable; - } - - /* - * This should only be used by Throwable::. - */ - static StackTrace makeStackTrace(Throwable ex) { - return StackTrace.dump(ex); - } - - /* - * This creates StackTrace for Thread::dumpThread to use. - */ - static StackTrace makeStackTrace() { - return StackTrace.dump(); - } - enum WalkerState { NEW, // the stream is new and stack walking has not started OPEN, // the stream is open when it is being traversed. CLOSED; // the stream is closed when the stack walking is done } - static abstract class AbstractStackWalker { + /** + * Subclass of AbstractStackWalker implements a specific stack walking logic. + * It needs to set up the frame buffer and stack walking mode. + * + * It initiates the VM stack walking via the callStackWalk method that serves + * as the anchored frame and VM will call up to AbstractStackWalker::doStackWalk. + * + * @param the type of the result returned from stack walking + * @param the type of the data gathered for each frame. + * For example, StackFrameInfo for StackWalker::walk or + * Class for StackWalker::getCallerClass + */ + static abstract class AbstractStackWalker { protected final StackWalker walker; protected final Thread thread; protected final int maxDepth; protected final long mode; - protected int depth; // traversed stack depth - protected FrameBuffer frameBuffer; // buffer for VM to fill in + protected int depth; // traversed stack depth + protected FrameBuffer frameBuffer; protected long anchor; // buffers to fill in stack frame information @@ -157,16 +138,13 @@ final class StackStreamFactory { private int toStackWalkMode(StackWalker walker, int mode) { int newMode = mode; if (walker.hasOption(Option.SHOW_HIDDEN_FRAMES) && - !fillCallerClassOnly(newMode) /* don't show hidden frames for getCallerClass */) + (mode & FILL_CLASS_REFS_ONLY) != FILL_CLASS_REFS_ONLY) newMode |= SHOW_HIDDEN_FRAMES; if (walker.hasLocalsOperandsOption()) newMode |= FILL_LIVE_STACK_FRAMES; return newMode; } - private boolean fillCallerClassOnly(int mode) { - return (mode|FILL_CLASS_REFS_ONLY) != FILL_CLASS_REFS_ONLY; - } /** * A callback method to consume the stack frames. This method is invoked * once stack walking begins (i.e. it is only invoked when walkFrames is called). @@ -179,7 +157,7 @@ final class StackStreamFactory { * * @return the number of consumed frames */ - protected abstract T consumeFrames(); + protected abstract R consumeFrames(); /** * Initialize FrameBuffer. Subclass should implement this method to @@ -252,7 +230,7 @@ final class StackStreamFactory { * Walks stack frames until {@link #consumeFrames} is done consuming * the frames it is interested in. */ - final T walk() { + final R walk() { checkState(NEW); try { // VM will need to stablize the stack before walking. It will invoke @@ -318,7 +296,7 @@ final class StackStreamFactory { } this.anchor = anchor; // set anchor for this bulk stack frame traversal - frameBuffer.setBatch(bufStartIndex, bufEndIndex); + frameBuffer.setBatch(depth, bufStartIndex, bufEndIndex); // traverse all frames and perform the action on the stack frames, if specified return consumeFrames(); @@ -381,15 +359,14 @@ final class StackStreamFactory { * If all fetched stack frames are traversed, AbstractStackWalker::fetchStackFrames will * fetch the next batch of stack frames to continue. */ - private T beginStackWalk() { + private R beginStackWalk() { // initialize buffers for VM to fill the stack frame info initFrameBuffer(); return callStackWalk(mode, 0, frameBuffer.curBatchFrameCount(), frameBuffer.startIndex(), - frameBuffer.classes, - frameBuffer.stackFrames); + frameBuffer.frames()); } /* @@ -404,8 +381,7 @@ final class StackStreamFactory { int endIndex = fetchStackFrames(mode, anchor, batchSize, startIndex, - frameBuffer.classes, - frameBuffer.stackFrames); + frameBuffer.frames()); if (isDebug) { System.out.format(" more stack walk requesting %d got %d to %d frames%n", batchSize, frameBuffer.startIndex(), endIndex); @@ -414,27 +390,26 @@ final class StackStreamFactory { if (numFrames == 0) { frameBuffer.freeze(); // done stack walking } else { - frameBuffer.setBatch(startIndex, endIndex); + frameBuffer.setBatch(depth, startIndex, endIndex); } return numFrames; } /** * Begins stack walking. This method anchors this frame and invokes - * AbstractStackWalker::doStackWalk after fetching the firt batch of stack frames. + * AbstractStackWalker::doStackWalk after fetching the first batch of stack frames. * * @param mode mode of stack walking * @param skipframes number of frames to be skipped before filling the frame buffer. * @param batchSize the batch size, max. number of elements to be filled in the frame buffers. * @param startIndex start index of the frame buffers to be filled. - * @param classes Classes buffer of the stack frames - * @param frames StackFrame buffer, or null + * @param frames Either a Class array, if mode is {@link #FILL_CLASS_REFS_ONLY} + * or a {@link StackFrameInfo} (or derivative) array otherwise. * @return Result of AbstractStackWalker::doStackWalk */ - private native T callStackWalk(long mode, int skipframes, + private native R callStackWalk(long mode, int skipframes, int batchSize, int startIndex, - Class[] classes, - StackFrame[] frames); + T[] frames); /** * Fetch the next batch of stack frames. @@ -443,185 +418,14 @@ final class StackStreamFactory { * @param anchor * @param batchSize the batch size, max. number of elements to be filled in the frame buffers. * @param startIndex start index of the frame buffers to be filled. - * @param classes Classes buffer of the stack frames - * @param frames StackFrame buffer, or null + * @param frames Either a Class array, if mode is {@link #FILL_CLASS_REFS_ONLY} + * or a {@link StackFrameInfo} (or derivative) array otherwise. * * @return the end index to the frame buffers */ private native int fetchStackFrames(long mode, long anchor, int batchSize, int startIndex, - Class[] classes, - StackFrame[] frames); - - - /* - * Frame buffer - * - * Each specialized AbstractStackWalker subclass may subclass the FrameBuffer. - */ - class FrameBuffer { - static final int START_POS = 2; // 0th and 1st elements are reserved - - // buffers for VM to fill stack frame info - int currentBatchSize; // current batch size - Class[] classes; // caller class for fast path - - StackFrame[] stackFrames; - - int origin; // index to the current traversed stack frame - int fence; // index to the last frame in the current batch - - FrameBuffer(int initialBatchSize) { - if (initialBatchSize < MIN_BATCH_SIZE) { - throw new IllegalArgumentException(initialBatchSize + " < minimum batch size: " + MIN_BATCH_SIZE); - } - this.origin = START_POS; - this.fence = 0; - this.currentBatchSize = initialBatchSize; - this.classes = new Class[currentBatchSize]; - } - - int curBatchFrameCount() { - return currentBatchSize-START_POS; - } - - /* - * Tests if this frame buffer is empty. All frames are fetched. - */ - final boolean isEmpty() { - return origin >= fence || (origin == START_POS && fence == 0); - } - - /* - * Freezes this frame buffer. The stack stream source is done fetching. - */ - final void freeze() { - origin = 0; - fence = 0; - } - - /* - * Tests if this frame buffer is active. It is inactive when - * it is done for traversal. All stack frames have been traversed. - */ - final boolean isActive() { - return origin > 0 && (fence == 0 || origin < fence || fence == currentBatchSize); - } - - /** - * Gets the class at the current frame and move to the next frame. - */ - final Class next() { - if (isEmpty()) { - throw new NoSuchElementException("origin=" + origin + " fence=" + fence); - } - Class c = classes[origin++]; - if (isDebug) { - int index = origin-1; - System.out.format(" next frame at %d: %s (origin %d fence %d)%n", index, - Objects.toString(c), index, fence); - } - return c; - } - - /** - * Gets the class at the current frame. - */ - final Class get() { - if (isEmpty()) { - throw new NoSuchElementException("origin=" + origin + " fence=" + fence); - } - return classes[origin]; - } - - /* - * Returns the index of the current frame. - */ - final int getIndex() { - return origin; - } - - /* - * Set the start and end index of a new batch of stack frames that have - * been filled in this frame buffer. - */ - final void setBatch(int startIndex, int endIndex) { - if (startIndex <= 0 || endIndex <= 0) - throw new IllegalArgumentException("startIndex=" + startIndex + " endIndex=" + endIndex); - - this.origin = startIndex; - this.fence = endIndex; - if (depth == 0 && fence > 0) { - // filter the frames due to the stack stream implementation - for (int i = START_POS; i < fence; i++) { - Class c = classes[i]; - if (isDebug) System.err.format(" frame %d: %s%n", i, c); - if (filterStackWalkImpl(c)) { - origin++; - } else { - break; - } - } - } - } - - /* - * Checks if the origin is the expected start index. - */ - final void check(int skipFrames) { - int index = skipFrames + START_POS; - if (origin != index) { - // stack walk must continue with the previous frame depth - throw new IllegalStateException("origin " + origin + " != " + index); - } - } - - // ------ subclass may override the following methods ------- - /** - * Resizes the buffers for VM to fill in the next batch of stack frames. - * The next batch will start at the given startIndex with the maximum number - * of elements. - * - *

    Subclass may override this method to manage the allocated buffers. - * - * @param startIndex the start index for the first frame of the next batch to fill in. - * @param elements the number of elements for the next batch to fill in. - * - */ - void resize(int startIndex, int elements) { - if (!isActive()) - throw new IllegalStateException("inactive frame buffer can't be resized"); - - int size = startIndex+elements; - if (classes.length < size) { - // copy the elements in classes array to the newly allocated one. - // classes[0] is a Thread object - Class[] prev = classes; - classes = new Class[size]; - System.arraycopy(prev, 0, classes, 0, START_POS); - } - currentBatchSize = size; - } - - /* - * Returns the start index for this frame buffer is refilled. - * - * This implementation reuses the allocated buffer for the next batch - * of stack frames. For subclass to retain the fetched stack frames, - * it should override this method to return the index at which the frame - * should be filled in for the next batch. - */ - int startIndex() { - return START_POS; - } - - /** - * Returns next StackFrame object in the current batch of stack frames - */ - StackFrame nextStackFrame() { - throw new InternalError("should not reach here"); - } - } + T[] frames); } /* @@ -629,46 +433,66 @@ final class StackStreamFactory { * * This class implements Spliterator::forEachRemaining and Spliterator::tryAdvance. */ - static class StackFrameTraverser extends AbstractStackWalker + static class StackFrameTraverser extends AbstractStackWalker implements Spliterator { static { stackWalkImplClasses.add(StackFrameTraverser.class); } private static final int CHARACTERISTICS = Spliterator.ORDERED | Spliterator.IMMUTABLE; - class Buffer extends FrameBuffer { - Buffer(int initialBatchSize) { + + final class StackFrameBuffer extends FrameBuffer { + private StackFrameInfo[] stackFrames; + StackFrameBuffer(int initialBatchSize) { super(initialBatchSize); - this.stackFrames = new StackFrame[initialBatchSize]; + this.stackFrames = new StackFrameInfo[initialBatchSize]; for (int i = START_POS; i < initialBatchSize; i++) { stackFrames[i] = new StackFrameInfo(walker); } } @Override - void resize(int startIndex, int elements) { - super.resize(startIndex, elements); - - int size = startIndex+elements; - if (stackFrames.length < size) { - stackFrames = new StackFrame[size]; - } - for (int i = startIndex(); i < size; i++) { - stackFrames[i] = new StackFrameInfo(walker); - } + StackFrameInfo[] frames() { + return stackFrames; } @Override - StackFrame nextStackFrame() { + void resize(int startIndex, int elements) { + if (!isActive()) + throw new IllegalStateException("inactive frame buffer can't be resized"); + + assert startIndex == START_POS : + "bad start index " + startIndex + " expected " + START_POS; + + int size = startIndex+elements; + if (stackFrames.length < size) { + StackFrameInfo[] newFrames = new StackFrameInfo[size]; + // copy initial magic... + System.arraycopy(stackFrames, 0, newFrames, 0, startIndex); + stackFrames = newFrames; + } + for (int i = startIndex; i < size; i++) { + stackFrames[i] = new StackFrameInfo(walker); + } + currentBatchSize = size; + } + + @Override + StackFrameInfo nextStackFrame() { if (isEmpty()) { throw new NoSuchElementException("origin=" + origin + " fence=" + fence); } - StackFrame frame = stackFrames[origin]; + StackFrameInfo frame = stackFrames[origin]; origin++; return frame; } + + @Override + final Class at(int index) { + return stackFrames[index].declaringClass; + } } final Function, ? extends T> function; // callback @@ -693,7 +517,7 @@ final class StackStreamFactory { return null; } - StackFrame frame = frameBuffer.nextStackFrame(); + StackFrameInfo frame = frameBuffer.nextStackFrame(); depth++; return frame; } @@ -710,7 +534,7 @@ final class StackStreamFactory { @Override protected void initFrameBuffer() { - this.frameBuffer = new Buffer(getNextBatchSize()); + this.frameBuffer = new StackFrameBuffer(getNextBatchSize()); } @Override @@ -781,7 +605,7 @@ final class StackStreamFactory { * CallerClassFinder is specialized to return Class for each stack frame. * StackFrame is not requested. */ - static class CallerClassFinder extends AbstractStackWalker { + static final class CallerClassFinder extends AbstractStackWalker> { static { stackWalkImplClasses.add(CallerClassFinder.class); } @@ -790,6 +614,54 @@ final class StackStreamFactory { CallerClassFinder(StackWalker walker) { super(walker, FILL_CLASS_REFS_ONLY); + assert (mode & FILL_CLASS_REFS_ONLY) == FILL_CLASS_REFS_ONLY + : "mode should contain FILL_CLASS_REFS_ONLY"; + } + + final class ClassBuffer extends FrameBuffer> { + Class[] classes; // caller class for fast path + ClassBuffer(int batchSize) { + super(batchSize); + classes = new Class[batchSize]; + } + + @Override + Class[] frames() { return classes;} + + @Override + final Class at(int index) { return classes[index];} + + + // ------ subclass may override the following methods ------- + /** + * Resizes the buffers for VM to fill in the next batch of stack frames. + * The next batch will start at the given startIndex with the maximum number + * of elements. + * + *

    Subclass may override this method to manage the allocated buffers. + * + * @param startIndex the start index for the first frame of the next batch to fill in. + * @param elements the number of elements for the next batch to fill in. + * + */ + @Override + void resize(int startIndex, int elements) { + if (!isActive()) + throw new IllegalStateException("inactive frame buffer can't be resized"); + + assert startIndex == START_POS : + "bad start index " + startIndex + " expected " + START_POS; + + int size = startIndex+elements; + if (classes.length < size) { + // copy the elements in classes array to the newly allocated one. + // classes[0] is a Thread object + Class[] prev = classes; + classes = new Class[size]; + System.arraycopy(prev, 0, classes, 0, startIndex); + } + currentBatchSize = size; + } } Class findCaller() { @@ -810,15 +682,15 @@ final class StackStreamFactory { if (isMethodHandleFrame(caller)) continue; frames[n++] = caller; } - - if (frames[1] == null) + if (frames[1] == null) { throw new IllegalStateException("no caller frame"); + } return n; } @Override protected void initFrameBuffer() { - this.frameBuffer = new FrameBuffer(getNextBatchSize()); + this.frameBuffer = new ClassBuffer(getNextBatchSize()); } @Override @@ -832,215 +704,64 @@ final class StackStreamFactory { } } - /* - * StackTrace caches all frames in the buffer. StackTraceElements are - * created lazily when Throwable::getStackTrace is called. - */ - static class StackTrace extends AbstractStackWalker { - static { - stackWalkImplClasses.add(StackTrace.class); - } - - class GrowableBuffer extends FrameBuffer { - GrowableBuffer(int initialBatchSize) { - super(initialBatchSize); - - this.stackFrames = new StackFrame[initialBatchSize]; - for (int i = START_POS; i < initialBatchSize; i++) { - stackFrames[i] = new StackFrameInfo(walker); - } - } - - /* - * Returns the next index to fill - */ - @Override - int startIndex() { - return origin; - } - - /** - * Initialize the buffers for VM to fill in the stack frame information. - * The next batch will start at the given startIndex to - * the length of the buffer. - */ - @Override - void resize(int startIndex, int elements) { - // Expand the frame buffer. - // Do not call super.resize that will reuse the filled elements - // in this frame buffer - int size = startIndex+elements; - if (classes.length < size) { - // resize the frame buffer - classes = Arrays.copyOf(classes, size); - stackFrames = Arrays.copyOf(stackFrames, size); - } - for (int i = startIndex; i < size; i++) { - stackFrames[i] = new StackFrameInfo(walker); - } - currentBatchSize = size; - } - - StackTraceElement get(int index) { - return new StackTraceElement(classes[index].getName(), "unknown", null, -1); - } - - /** - * Returns an array of StackTraceElement for all stack frames cached in - * this StackTrace object. - *

    - * This method is intended for Throwable::getOurStackTrace use only. - */ - StackTraceElement[] toStackTraceElements() { - int startIndex = START_POS; - for (int i = startIndex; i < classes.length; i++) { - if (classes[i] != null && filterStackWalkImpl(classes[i])) { - startIndex++; - } else { - break; - } - } - - // VM fills in the method name, filename, line number info - StackFrameInfo.fillInStackFrames(0, stackFrames, startIndex, startIndex + depth); - - StackTraceElement[] stes = new StackTraceElement[depth]; - for (int i = startIndex, j = 0; i < classes.length && j < depth; i++, j++) { - if (isDebug) { - System.err.println("StackFrame: " + i + " " + stackFrames[i]); - } - stes[j] = stackFrames[i].toStackTraceElement(); - } - return stes; - } - } - - private static final int MAX_STACK_FRAMES = 1024; - private static final StackWalker STACKTRACE_WALKER = - StackWalker.newInstanceNoCheck(EnumSet.of(Option.SHOW_REFLECT_FRAMES)); - - private StackTraceElement[] stes; - static StackTrace dump() { - return new StackTrace(); - } - - static StackTrace dump(Throwable ex) { - return new StackTrace(ex); - } - - private StackTrace() { - this(STACKTRACE_WALKER, DEFAULT_MODE); - } - - /* - * Throwable::fillInStackTrace and of Throwable and subclasses - * are filtered in the VM. - */ - private StackTrace(Throwable ex) { - this(STACKTRACE_WALKER, FILTER_FILL_IN_STACKTRACE); // skip Throwable::init frames - if (isDebug) { - System.err.println("dump stack for " + ex.getClass().getName()); - } - } - - StackTrace(StackWalker walker, int mode) { - super(walker, mode, MAX_STACK_FRAMES); - - // snapshot the stack trace - walk(); - } - - @Override - protected Integer consumeFrames() { - // traverse all frames and perform the action on the stack frames, if specified - int n = 0; - while (n < maxDepth && nextFrame() != null) { - n++; - } - return n; - } - - @Override - protected void initFrameBuffer() { - this.frameBuffer = new GrowableBuffer(getNextBatchSize()); - } - - // TODO: implement better heuristic - @Override - protected int batchSize(int lastBatchFrameCount) { - // chunk size of VM backtrace is 32 - return lastBatchFrameCount == 0 ? 32 : 32; - } - - /** - * Returns an array of StackTraceElement for all stack frames cached in - * this StackTrace object. - *

    - * This method is intended for Throwable::getOurStackTrace use only. - */ - synchronized StackTraceElement[] getStackTraceElements() { - if (stes == null) { - stes = ((GrowableBuffer) frameBuffer).toStackTraceElements(); - // release the frameBuffer memory - frameBuffer = null; - } - return stes; - } - - /* - * Prints stack trace to the given PrintStream. - * - * Further implementation could skip creating StackTraceElement objects - * print directly to the PrintStream. - */ - void printStackTrace(PrintStream s) { - StackTraceElement[] stes = getStackTraceElements(); - synchronized (s) { - s.println("Stack trace"); - for (StackTraceElement traceElement : stes) - s.println("\tat " + traceElement); - } - } - } - - static class LiveStackInfoTraverser extends StackFrameTraverser { + static final class LiveStackInfoTraverser extends StackFrameTraverser { static { stackWalkImplClasses.add(LiveStackInfoTraverser.class); } // VM will fill in all method info and live stack info directly in StackFrameInfo - class Buffer extends FrameBuffer { - Buffer(int initialBatchSize) { + final class LiveStackFrameBuffer extends FrameBuffer { + private LiveStackFrameInfo[] stackFrames; + LiveStackFrameBuffer(int initialBatchSize) { super(initialBatchSize); - this.stackFrames = new StackFrame[initialBatchSize]; + this.stackFrames = new LiveStackFrameInfo[initialBatchSize]; for (int i = START_POS; i < initialBatchSize; i++) { stackFrames[i] = new LiveStackFrameInfo(walker); } } @Override - void resize(int startIndex, int elements) { - super.resize(startIndex, elements); - int size = startIndex + elements; + LiveStackFrameInfo[] frames() { + return stackFrames; + } + @Override + void resize(int startIndex, int elements) { + if (!isActive()) { + throw new IllegalStateException("inactive frame buffer can't be resized"); + } + assert startIndex == START_POS : + "bad start index " + startIndex + " expected " + START_POS; + + int size = startIndex + elements; if (stackFrames.length < size) { - this.stackFrames = new StackFrame[size]; + LiveStackFrameInfo[] newFrames = new LiveStackFrameInfo[size]; + // copy initial magic... + System.arraycopy(stackFrames, 0, newFrames, 0, startIndex); + stackFrames = newFrames; } for (int i = startIndex(); i < size; i++) { stackFrames[i] = new LiveStackFrameInfo(walker); } + + currentBatchSize = size; } @Override - StackFrame nextStackFrame() { + LiveStackFrameInfo nextStackFrame() { if (isEmpty()) { throw new NoSuchElementException("origin=" + origin + " fence=" + fence); } - StackFrame frame = stackFrames[origin]; + LiveStackFrameInfo frame = stackFrames[origin]; origin++; return frame; } + + @Override + final Class at(int index) { + return stackFrames[index].declaringClass; + } } LiveStackInfoTraverser(StackWalker walker, @@ -1050,7 +771,183 @@ final class StackStreamFactory { @Override protected void initFrameBuffer() { - this.frameBuffer = new Buffer(getNextBatchSize()); + this.frameBuffer = new LiveStackFrameBuffer(getNextBatchSize()); + } + } + + /* + * Frame buffer + * + * Each specialized AbstractStackWalker subclass may subclass the FrameBuffer. + */ + static abstract class FrameBuffer { + static final int START_POS = 2; // 0th and 1st elements are reserved + + // buffers for VM to fill stack frame info + int currentBatchSize; // current batch size + int origin; // index to the current traversed stack frame + int fence; // index to the last frame in the current batch + + FrameBuffer(int initialBatchSize) { + if (initialBatchSize < MIN_BATCH_SIZE) { + throw new IllegalArgumentException(initialBatchSize + + " < minimum batch size: " + MIN_BATCH_SIZE); + } + this.origin = START_POS; + this.fence = 0; + this.currentBatchSize = initialBatchSize; + } + + /** + * Returns an array of frames that may be used to store frame objects + * when walking the stack. + * + * May be an array of {@code Class} if the {@code AbstractStackWalker} + * mode is {@link #FILL_CLASS_REFS_ONLY}, or an array of + * {@link StackFrameInfo} (or derivative) array otherwise. + * + * @return An array of frames that may be used to store frame objects + * when walking the stack. Must not be null. + */ + abstract F[] frames(); // must not return null + + /** + * Resizes the buffers for VM to fill in the next batch of stack frames. + * The next batch will start at the given startIndex with the maximum number + * of elements. + * + *

    Subclass may override this method to manage the allocated buffers. + * + * @param startIndex the start index for the first frame of the next batch to fill in. + * @param elements the number of elements for the next batch to fill in. + * + */ + abstract void resize(int startIndex, int elements); + + /** + * Return the class at the given position in the current batch. + * @param index the position of the frame. + * @return the class at the given position in the current batch. + */ + abstract Class at(int index); + + // ------ subclass may override the following methods ------- + + /* + * Returns the start index for this frame buffer is refilled. + * + * This implementation reuses the allocated buffer for the next batch + * of stack frames. For subclass to retain the fetched stack frames, + * it should override this method to return the index at which the frame + * should be filled in for the next batch. + */ + int startIndex() { + return START_POS; + } + + /** + * Returns next StackFrame object in the current batch of stack frames + */ + F nextStackFrame() { + throw new InternalError("should not reach here"); + } + + // ------ FrameBuffer implementation ------ + + final int curBatchFrameCount() { + return currentBatchSize-START_POS; + } + + /* + * Tests if this frame buffer is empty. All frames are fetched. + */ + final boolean isEmpty() { + return origin >= fence || (origin == START_POS && fence == 0); + } + + /* + * Freezes this frame buffer. The stack stream source is done fetching. + */ + final void freeze() { + origin = 0; + fence = 0; + } + + /* + * Tests if this frame buffer is active. It is inactive when + * it is done for traversal. All stack frames have been traversed. + */ + final boolean isActive() { + return origin > 0 && (fence == 0 || origin < fence || fence == currentBatchSize); + } + + /** + * Gets the class at the current frame and move to the next frame. + */ + final Class next() { + if (isEmpty()) { + throw new NoSuchElementException("origin=" + origin + " fence=" + fence); + } + Class c = at(origin); + origin++; + if (isDebug) { + int index = origin-1; + System.out.format(" next frame at %d: %s (origin %d fence %d)%n", index, + Objects.toString(c), index, fence); + } + return c; + } + + /** + * Gets the class at the current frame. + */ + final Class get() { + if (isEmpty()) { + throw new NoSuchElementException("origin=" + origin + " fence=" + fence); + } + return at(origin); + } + + /* + * Returns the index of the current frame. + */ + final int getIndex() { + return origin; + } + + /* + * Set the start and end index of a new batch of stack frames that have + * been filled in this frame buffer. + */ + final void setBatch(int depth, int startIndex, int endIndex) { + if (startIndex <= 0 || endIndex <= 0) + throw new IllegalArgumentException("startIndex=" + startIndex + " endIndex=" + endIndex); + + this.origin = startIndex; + this.fence = endIndex; + if (depth == 0 && fence > 0) { + // filter the frames due to the stack stream implementation + for (int i = START_POS; i < fence; i++) { + Class c = at(i); + if (isDebug) System.err.format(" frame %d: %s%n", i, c); + if (filterStackWalkImpl(c)) { + origin++; + } else { + break; + } + } + } + } + + /* + * Checks if the origin is the expected start index. + */ + final void check(int skipFrames) { + int index = skipFrames + START_POS; + if (origin != index) { + // stack walk must continue with the previous frame depth + throw new IllegalStateException("origin " + origin + " != " + index); + } } } diff --git a/jdk/src/java.base/share/classes/java/lang/Thread.java b/jdk/src/java.base/share/classes/java/lang/Thread.java index eb47a05427d..39afad9795f 100644 --- a/jdk/src/java.base/share/classes/java/lang/Thread.java +++ b/jdk/src/java.base/share/classes/java/lang/Thread.java @@ -1388,7 +1388,7 @@ class Thread implements Runnable { * This method is used only for debugging. */ public static void dumpStack() { - StackStreamFactory.makeStackTrace().printStackTrace(System.err); + new Exception("Stack trace").printStackTrace(); } /** @@ -1610,8 +1610,7 @@ class Thread implements Runnable { } return stackTrace; } else { - // Don't need JVM help for current thread - return StackStreamFactory.makeStackTrace().getStackTraceElements(); + return (new Exception()).getStackTrace(); } } diff --git a/jdk/src/java.base/share/classes/java/lang/Throwable.java b/jdk/src/java.base/share/classes/java/lang/Throwable.java index 72a3455e637..a609719c9cd 100644 --- a/jdk/src/java.base/share/classes/java/lang/Throwable.java +++ b/jdk/src/java.base/share/classes/java/lang/Throwable.java @@ -785,11 +785,7 @@ public class Throwable implements Serializable { public synchronized Throwable fillInStackTrace() { if (stackTrace != null || backtrace != null /* Out of protocol state */ ) { - if (backtrace == null && StackStreamFactory.useStackTrace(this)) { - backtrace = StackStreamFactory.makeStackTrace(this); - } else { - fillInStackTrace(0); - } + fillInStackTrace(0); stackTrace = UNASSIGNED_STACK; } return this; @@ -830,15 +826,11 @@ public class Throwable implements Serializable { // backtrace if this is the first call to this method if (stackTrace == UNASSIGNED_STACK || (stackTrace == null && backtrace != null) /* Out of protocol state */) { - if (backtrace instanceof StackStreamFactory.StackTrace) { - stackTrace = ((StackStreamFactory.StackTrace)backtrace).getStackTraceElements(); - } else { - stackTrace = new StackTraceElement[depth]; - for (int i = 0; i < depth; i++) { - stackTrace[i] = new StackTraceElement(); - } - getStackTraceElements(stackTrace); + stackTrace = new StackTraceElement[depth]; + for (int i = 0; i < depth; i++) { + stackTrace[i] = new StackTraceElement(); } + getStackTraceElements(stackTrace); } else if (stackTrace == null) { return UNASSIGNED_STACK; } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java index da91db90da3..5945bcc1f85 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -1132,6 +1132,10 @@ import java.util.Objects; public Object newMemberName() { return new MemberName(); } + public String getName(Object mname) { + MemberName memberName = (MemberName)mname; + return memberName.getName(); + } }); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java index 776c24dc95a..1a4aba5d79b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java @@ -30,4 +30,9 @@ public interface JavaLangInvokeAccess { * Create a new MemberName instance */ Object newMemberName(); + + /** + * Returns the name for the given MemberName + */ + String getName(Object mname); } diff --git a/jdk/src/java.base/share/native/include/jvm.h b/jdk/src/java.base/share/native/include/jvm.h index c5fc7e91178..2011e58352a 100644 --- a/jdk/src/java.base/share/native/include/jvm.h +++ b/jdk/src/java.base/share/native/include/jvm.h @@ -179,7 +179,6 @@ JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray elements) */ enum { JVM_STACKWALK_FILL_CLASS_REFS_ONLY = 0x2, - JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE = 0x10, JVM_STACKWALK_SHOW_HIDDEN_FRAMES = 0x20, JVM_STACKWALK_FILL_LIVE_STACK_FRAMES = 0x100 }; @@ -187,23 +186,15 @@ enum { JNIEXPORT jobject JNICALL JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jint skip_frames, jint frame_count, jint start_index, - jobjectArray classes, jobjectArray frames); JNIEXPORT jint JNICALL JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, jint frame_count, jint start_index, - jobjectArray classes, jobjectArray frames); JNIEXPORT void JNICALL -JVM_FillStackFrames(JNIEnv* env, jclass cls, - jint start_index, - jobjectArray stackFrames, - jint from_index, jint toIndex); - -JNIEXPORT void JNICALL -JVM_SetMethodInfo(JNIEnv* env, jobject frame); +JVM_ToStackTraceElement(JNIEnv* env, jobject frame, jobject stackElement); JNIEXPORT jobjectArray JNICALL JVM_GetVmArguments(JNIEnv *env); diff --git a/jdk/src/java.base/share/native/libjava/StackFrameInfo.c b/jdk/src/java.base/share/native/libjava/StackFrameInfo.c index f7930a45924..41c021a2027 100644 --- a/jdk/src/java.base/share/native/libjava/StackFrameInfo.c +++ b/jdk/src/java.base/share/native/libjava/StackFrameInfo.c @@ -38,22 +38,10 @@ /* * Class: java_lang_StackFrameInfo - * Method: fillInStackFrames - * Signature: (I[Ljava/lang/Object;[Ljava/lang/Object;II)V + * Method: toStackTraceElement0 + * Signature: (Ljava/lang/StackTraceElement;)V */ -JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_fillInStackFrames - (JNIEnv *env, jclass dummy, jint startIndex, - jobjectArray stackFrames, jint fromIndex, jint toIndex) { - JVM_FillStackFrames(env, dummy, startIndex, - stackFrames, fromIndex, toIndex); -} - -/* - * Class: java_lang_StackFrameInfo - * Method: setMethodInfo - * Signature: (Ljava/lang/Class;)V - */ -JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_setMethodInfo - (JNIEnv *env, jobject stackframeinfo) { - JVM_SetMethodInfo(env, stackframeinfo); +JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_toStackTraceElement0 + (JNIEnv *env, jobject stackframeinfo, jobject stacktraceinfo) { + JVM_ToStackTraceElement(env, stackframeinfo, stacktraceinfo); } diff --git a/jdk/src/java.base/share/native/libjava/StackStreamFactory.c b/jdk/src/java.base/share/native/libjava/StackStreamFactory.c index c23e9d04918..099b09b3cc6 100644 --- a/jdk/src/java.base/share/native/libjava/StackStreamFactory.c +++ b/jdk/src/java.base/share/native/libjava/StackStreamFactory.c @@ -45,7 +45,6 @@ JNIEXPORT jboolean JNICALL Java_java_lang_StackStreamFactory_checkStackWalkModes (JNIEnv *env, jclass dummy) { return JVM_STACKWALK_FILL_CLASS_REFS_ONLY == java_lang_StackStreamFactory_FILL_CLASS_REFS_ONLY && - JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE == java_lang_StackStreamFactory_FILTER_FILL_IN_STACKTRACE && JVM_STACKWALK_SHOW_HIDDEN_FRAMES == java_lang_StackStreamFactory_SHOW_HIDDEN_FRAMES && JVM_STACKWALK_FILL_LIVE_STACK_FRAMES == java_lang_StackStreamFactory_FILL_LIVE_STACK_FRAMES; } @@ -53,26 +52,26 @@ JNIEXPORT jboolean JNICALL Java_java_lang_StackStreamFactory_checkStackWalkModes /* * Class: java_lang_StackStreamFactory_AbstractStackWalker * Method: callStackWalk - * Signature: (JIII[Ljava/lang/Class;[Ljava/lang/StackWalker/StackFrame;)Ljava/lang/Object; + * Signature: (JIII[Ljava/lang/Object;)Ljava/lang/Object; */ JNIEXPORT jobject JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk (JNIEnv *env, jobject stackstream, jlong mode, jint skipFrames, jint batchSize, jint startIndex, - jobjectArray classes, jobjectArray frames) + jobjectArray frames) { return JVM_CallStackWalk(env, stackstream, mode, skipFrames, batchSize, - startIndex, classes, frames); + startIndex, frames); } /* * Class: java_lang_StackStreamFactory_AbstractStackWalker * Method: fetchStackFrames - * Signature: (JJII[Ljava/lang/Class;[Ljava/lang/StackWalker/StackFrame;)I + * Signature: (JJII[Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames (JNIEnv *env, jobject stackstream, jlong mode, jlong anchor, jint batchSize, jint startIndex, - jobjectArray classes, jobjectArray frames) + jobjectArray frames) { return JVM_MoreStackWalk(env, stackstream, mode, anchor, batchSize, - startIndex, classes, frames); + startIndex, frames); } diff --git a/jdk/test/java/lang/StackWalker/DumpStackTest.java b/jdk/test/java/lang/StackWalker/DumpStackTest.java index 667e325a8f0..2aa97d7c93e 100644 --- a/jdk/test/java/lang/StackWalker/DumpStackTest.java +++ b/jdk/test/java/lang/StackWalker/DumpStackTest.java @@ -28,9 +28,6 @@ * This test should also been run against jdk9 successfully except of * VM option MemberNameInStackFrame. * @run main/othervm DumpStackTest - * @run main/othervm -Dstackwalk.newThrowable=false DumpStackTest - * @run main/othervm -Dstackwalk.newThrowable=true -XX:-MemberNameInStackFrame DumpStackTest - * @run main/othervm -Dstackwalk.newThrowable=true -XX:+MemberNameInStackFrame DumpStackTest */ import java.lang.invoke.MethodHandle; diff --git a/jdk/test/java/lang/StackWalker/GetCallerClassTest.java b/jdk/test/java/lang/StackWalker/GetCallerClassTest.java index 53a3f70c52a..8276d721087 100644 --- a/jdk/test/java/lang/StackWalker/GetCallerClassTest.java +++ b/jdk/test/java/lang/StackWalker/GetCallerClassTest.java @@ -25,8 +25,7 @@ * @test * @bug 8140450 * @summary Basic test for StackWalker.getCallerClass() - * @run main/othervm -XX:-MemberNameInStackFrame GetCallerClassTest - * @run main/othervm -XX:+MemberNameInStackFrame GetCallerClassTest + * @run main/othervm GetCallerClassTest * @run main/othervm GetCallerClassTest sm */ diff --git a/jdk/test/java/lang/StackWalker/StackWalkTest.java b/jdk/test/java/lang/StackWalker/StackWalkTest.java index 7bbcc6150f8..5c4782fb46a 100644 --- a/jdk/test/java/lang/StackWalker/StackWalkTest.java +++ b/jdk/test/java/lang/StackWalker/StackWalkTest.java @@ -44,10 +44,6 @@ import jdk.testlibrary.RandomFactory; * @run main/othervm/java.security.policy=stackwalktest.policy StackWalkTest * @run main/othervm StackWalkTest -random:50 * @run main/othervm/java.security.policy=stackwalktest.policy StackWalkTest -random:50 - * @run main/othervm -XX:-MemberNameInStackFrame -Dstackwalk.newThrowable=false StackWalkTest -random:50 - * @run main/othervm -XX:-MemberNameInStackFrame -Dstackwalk.newThrowable=true StackWalkTest -random:50 - * @run main/othervm -XX:+MemberNameInStackFrame -Dstackwalk.newThrowable=false StackWalkTest -random:50 - * @run main/othervm -XX:+MemberNameInStackFrame -Dstackwalk.newThrowable=true StackWalkTest -random:50 * @author danielfuchs, bchristi * @key randomness */ diff --git a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java index b5f8653bc1b..d9cfcf6aba5 100644 --- a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java +++ b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java @@ -40,8 +40,7 @@ import static java.lang.StackWalker.Option.*; * @summary Verify stack trace information obtained with respect to StackWalker * options, when the stack contains lambdas, method handle invoke * virtual calls, and reflection. - * @run main/othervm -XX:-MemberNameInStackFrame VerifyStackTrace - * @run main/othervm -XX:+MemberNameInStackFrame VerifyStackTrace + * @run main/othervm VerifyStackTrace * @run main/othervm/java.security.policy=stackwalk.policy VerifyStackTrace * @author danielfuchs */ From c83f454c576ec65c108e24ffc9b05f59491cc0b8 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Mon, 11 Apr 2016 21:07:34 +0300 Subject: [PATCH 067/222] 6832045: DefaultSynthStyle.{getStateInfo,getMatchCount) should use Integer.bitCount Reviewed-by: alexsch, twisti --- .../javax/swing/plaf/nimbus/NimbusStyle.java | 13 ++------- .../swing/plaf/synth/DefaultSynthStyle.java | 28 ++----------------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java index 7fdbe384f57..ef49aab21a4 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -995,16 +995,7 @@ public final class NimbusStyle extends SynthStyle { // StateInfo match, otherwise a StateInfo with // SELECTED | ENABLED would match ENABLED, which we // don't want. - - // This comes from BigInteger.bitCnt - int bitCount = oState; - bitCount -= (0xaaaaaaaa & bitCount) >>> 1; - bitCount = (bitCount & 0x33333333) + ((bitCount >>> 2) & - 0x33333333); - bitCount = bitCount + (bitCount >>> 4) & 0x0f0f0f0f; - bitCount += bitCount >>> 8; - bitCount += bitCount >>> 16; - bitCount = bitCount & 0xff; + int bitCount = Integer.bitCount(oState); if (bitCount > bestCount) { bestIndex = counter; bestCount = bitCount; diff --git a/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java b/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java index 8e4c2159679..587aceb454f 100644 --- a/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java +++ b/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -645,16 +645,7 @@ public class DefaultSynthStyle extends SynthStyle implements Cloneable { // StateInfo match, otherwise a StateInfo with // SELECTED | ENABLED would match ENABLED, which we // don't want. - - // This comes from BigInteger.bitCnt - int bitCount = oState; - bitCount -= (0xaaaaaaaa & bitCount) >>> 1; - bitCount = (bitCount & 0x33333333) + ((bitCount >>> 2) & - 0x33333333); - bitCount = bitCount + (bitCount >>> 4) & 0x0f0f0f0f; - bitCount += bitCount >>> 8; - bitCount += bitCount >>> 16; - bitCount = bitCount & 0xff; + int bitCount = Integer.bitCount(oState); if (bitCount > bestCount) { bestIndex = counter; bestCount = bitCount; @@ -882,21 +873,6 @@ public class DefaultSynthStyle extends SynthStyle implements Cloneable { return state; } - /** - * Returns the number of states that are similar between the - * ComponentState this StateInfo represents and val. - */ - private int getMatchCount(int val) { - // This comes from BigInteger.bitCnt - val &= state; - val -= (0xaaaaaaaa & val) >>> 1; - val = (val & 0x33333333) + ((val >>> 2) & 0x33333333); - val = val + (val >>> 4) & 0x0f0f0f0f; - val += val >>> 8; - val += val >>> 16; - return val & 0xff; - } - /** * Creates and returns a copy of this StateInfo. * From 9a51f0b1eb070de1b16dcc6a19c2149a778bd807 Mon Sep 17 00:00:00 2001 From: Peter Brunet Date: Mon, 11 Apr 2016 21:41:43 -0500 Subject: [PATCH 068/222] 8150056: Remove package access restriction of com.sun.java.accessibility.util.internal Remove use of Class.forName; remove package access check from getAccessible Reviewed-by: prr, asmotrak, ahgross --- .../java/accessibility/util/Translator.java | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java index 224b5375283..bb762ad0b42 100644 --- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * 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,13 +26,11 @@ package com.sun.java.accessibility.util; -import java.lang.*; +import com.sun.java.accessibility.util.internal.*; import java.beans.*; import java.util.*; import java.awt.*; import java.awt.event.*; -import java.awt.image.*; -import java.security.AccessControlException; // Do not import Swing classes. This module is intended to work // with both Swing and AWT. // import javax.swing.*; @@ -77,12 +75,26 @@ public class Translator extends AccessibleContext if (c == null) { return null; } - try { - t = Class.forName("com.sun.java.accessibility.util.internal." - + c.getSimpleName() - + "Translator"); + switch (c.getSimpleName()) { + case "Button": + t = ButtonTranslator.class; + break; + case "Checkbox": + t = CheckboxTranslator.class; + break; + case "Label": + t = LabelTranslator.class; + break; + case "List": + t = ListTranslator.class; + break; + case "TextComponent": + t = TextComponentTranslator.class; + break; + } + if (t != null) { return t; - } catch (Exception e) { + } else { return getTranslatorClass(c.getSuperclass()); } } @@ -106,10 +118,6 @@ public class Translator extends AccessibleContext if (o instanceof Accessible) { a = (Accessible)o; } else { - // About to "newInstance" an object of a class of a restricted package - // so ensure the caller is allowed access to that package. - String pkg = "com.sun.java.accessibility.util.internal"; - System.getSecurityManager().checkPackageAccess(pkg); Class translatorClass = getTranslatorClass(o.getClass()); if (translatorClass != null) { try { From a64d3028c346b5ae1b8c0eba04f18bc6367173b3 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Tue, 12 Apr 2016 00:43:57 -0700 Subject: [PATCH 069/222] 8153902: remove com/sun/jdi/InterfaceMethodsTest.java, com/sun/jdi/InvokeTest.java from ProblemList Enable the jdi tests again Reviewed-by: sundar --- jdk/test/ProblemList.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index cec532e0634..11e567fc1fa 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -333,10 +333,6 @@ com/sun/jdi/CatchPatternTest.sh 8068645 generic- com/sun/jdi/GetLocalVariables4Test.sh 8067354 windows-all -com/sun/jdi/InterfaceMethodsTest.java 8152586 generic-all - -com/sun/jdi/InvokeTest.java 8152586 generic-all - ############################################################################ # jdk_util From a3bb2ad45267d514411793d5bef9e928cece907a Mon Sep 17 00:00:00 2001 From: Ambarish Rapte Date: Tue, 12 Apr 2016 14:40:58 +0530 Subject: [PATCH 070/222] 6191390: Action Event triggered by list does not reflect the modifiers properly on win32 Reviewed-by: serb, psadhukhan --- .../classes/sun/awt/X11/XBaseMenuWindow.java | 4 +- .../classes/sun/awt/X11/XMenuItemPeer.java | 4 +- .../native/libawt/windows/awt_Button.cpp | 2 +- .../native/libawt/windows/awt_Component.cpp | 22 +++ .../native/libawt/windows/awt_Component.h | 1 + .../native/libawt/windows/awt_List.cpp | 2 +- .../native/libawt/windows/awt_MenuItem.cpp | 2 +- .../native/libawt/windows/awt_TrayIcon.cpp | 6 +- .../ActionEventTest/ActionEventTest.java | 109 +++++++++++++++ .../List/ActionEventTest/ActionEventTest.java | 100 +++++++++++++ .../ActionEventTest/ActionEventTest.java | 104 ++++++++++++++ .../ActionEventTest/ActionEventTest.java | 132 ++++++++++++++++++ 12 files changed, 478 insertions(+), 10 deletions(-) create mode 100644 jdk/test/java/awt/Button/ActionEventTest/ActionEventTest.java create mode 100644 jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java create mode 100644 jdk/test/java/awt/MenuBar/ActionEventTest/ActionEventTest.java create mode 100644 jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java index 85481f55c46..bb74478d299 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java @@ -1087,7 +1087,7 @@ public abstract class XBaseMenuWindow extends XWindow { } } else { //Invoke action event - item.action(mouseEvent.getWhen()); + item.action(mouseEvent.getWhen(), mouseEvent.getModifiers()); ungrabInput(); } } else { @@ -1200,7 +1200,7 @@ public abstract class XBaseMenuWindow extends XWindow { if (citem instanceof XMenuPeer) { cwnd.selectItem(citem, true); } else if (citem != null) { - citem.action(event.getWhen()); + citem.action(event.getWhen(), event.getModifiers()); ungrabInput(); } break; diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java index aa1c85d7908..d4e578961be 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java @@ -323,11 +323,11 @@ public class XMenuItemPeer implements MenuItemPeer { * on menu item. * @param when the timestamp of action event */ - void action(long when) { + void action(long when, int modifiers) { if (!isSeparator() && isTargetItemEnabled()) { XWindow.postEventStatic(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, getTargetActionCommand(), when, - 0)); + modifiers)); } } /************************************************ diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp index f0550a9aa5d..e76582bf363 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp @@ -187,7 +187,7 @@ void AwtButton::NotifyListeners() { DoCallback("handleAction", "(JI)V", ::JVM_CurrentTimeMillis(NULL, 0), - (jint)AwtComponent::GetJavaModifiers()); + (jint)AwtComponent::GetActionModifiers()); } MsgRouting diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp index d5224df0b62..746b1114488 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -2587,6 +2588,27 @@ jint AwtComponent::GetShiftKeyLocation(UINT vkey, UINT flags) return java_awt_event_KeyEvent_KEY_LOCATION_LEFT; } +/* Returns Java ActionEvent modifieres. + * When creating ActionEvent, modifiers provided by ActionEvent + * class should be set. + */ +jint +AwtComponent::GetActionModifiers() +{ + jint modifiers = GetJavaModifiers(); + + if (modifiers & java_awt_event_InputEvent_CTRL_DOWN_MASK) { + modifiers |= java_awt_event_ActionEvent_CTRL_MASK; + } + if (modifiers & java_awt_event_InputEvent_SHIFT_DOWN_MASK) { + modifiers |= java_awt_event_ActionEvent_SHIFT_MASK; + } + if (modifiers & java_awt_event_InputEvent_ALT_DOWN_MASK) { + modifiers |= java_awt_event_ActionEvent_ALT_MASK; + } + return modifiers; +} + /* Returns Java extended InputEvent modifieres. * Since ::GetKeyState returns current state and Java modifiers represent * state before event, modifier on changed key are inverted. diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h index 83c6d8b8a4e..135ac39b874 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h @@ -438,6 +438,7 @@ public: static void InitDynamicKeyMapTable(); static void BuildDynamicKeyMapTable(); static jint GetJavaModifiers(); + static jint GetActionModifiers(); static jint GetButton(int mouseButton); static UINT GetButtonMK(int mouseButton); static UINT WindowsKeyToJavaKey(UINT windowsKey, UINT modifiers, UINT character, BOOL isDeadKey); diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.cpp index 39016b9ab59..4c32a472996 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.cpp @@ -536,7 +536,7 @@ AwtList::WmNotify(UINT notifyCode) else if (notifyCode == LBN_DBLCLK) { DoCallback("handleAction", "(IJI)V", nCurrentSelection, ::JVM_CurrentTimeMillis(NULL, 0), - (jint)AwtComponent::GetJavaModifiers()); + (jint)AwtComponent::GetActionModifiers()); } } } diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp index ba0488187c5..80fc977e00d 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp @@ -667,7 +667,7 @@ void AwtMenuItem::DoCommand() DoCallback("handleAction", "(Z)V", ((nState & MF_CHECKED) == 0)); } else { DoCallback("handleAction", "(JI)V", ::JVM_CurrentTimeMillis(NULL, 0), - (jint)AwtComponent::GetJavaModifiers()); + (jint)AwtComponent::GetActionModifiers()); } } diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp index ef376f31a3b..56280a583ac 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp @@ -409,7 +409,7 @@ MsgRouting AwtTrayIcon::WmBalloonUserClick(UINT flags, int x, int y) MSG msg; AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, ::JVM_CurrentTimeMillis(NULL, 0), - AwtComponent::GetJavaModifiers(), &msg); + AwtComponent::GetActionModifiers(), &msg); } return mrConsume; } @@ -425,7 +425,7 @@ MsgRouting AwtTrayIcon::WmKeySelect(UINT flags, int x, int y) MSG msg; AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, ::JVM_CurrentTimeMillis(NULL, 0), - AwtComponent::GetJavaModifiers(), &msg); + AwtComponent::GetActionModifiers(), &msg); } lastKeySelectTime = now; @@ -442,7 +442,7 @@ MsgRouting AwtTrayIcon::WmSelect(UINT flags, int x, int y) MSG msg; AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, ::JVM_CurrentTimeMillis(NULL, 0), - AwtComponent::GetJavaModifiers(), &msg); + AwtComponent::GetActionModifiers(), &msg); } return mrConsume; } diff --git a/jdk/test/java/awt/Button/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/Button/ActionEventTest/ActionEventTest.java new file mode 100644 index 00000000000..9c6317d9a7d --- /dev/null +++ b/jdk/test/java/awt/Button/ActionEventTest/ActionEventTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6191390 + * @summary Verify that ActionEvent is received with correct modifiers set. + * @run main/manual ActionEventTest + */ + +import java.awt.AWTException; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Button; +import java.awt.TextArea; +import java.awt.Robot; +import java.awt.Point; +import java.awt.event.InputEvent; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +public class ActionEventTest extends Frame { + Button button; + Robot robot; + TextArea instructions; + public static boolean isProgInterruption = false; + static Thread mainThread = null; + static int sleepTime = 300000; + + public ActionEventTest() { + try { + robot = new Robot(); + } catch(AWTException e) { + throw new RuntimeException(e.getMessage()); + } + + button = new Button("ClickMe"); + button.setEnabled(true); + + instructions = new TextArea(10, 50); + instructions.setText( + " This is a manual test\n" + + " Keep the Alt, Shift & Ctrl Keys pressed &\n" + + " Click 'ClickMe' button with left mouse button\n" + + " Test exits automatically after mouse click."); + + add(button); + add(instructions); + setSize(400,400); + setLayout(new FlowLayout()); + pack(); + setVisible(true); + robot.waitForIdle(); + + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + int md = ae.getModifiers(); + int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK + | ActionEvent.SHIFT_MASK; + + isProgInterruption = true; + mainThread.interrupt(); + if ((md & expectedMask) != expectedMask) { + throw new RuntimeException("Action Event modifiers" + + " are not set correctly."); + } + } + }); + } + + public static void main(String args[]) throws Exception { + mainThread = Thread.currentThread(); + ActionEventTest test = new ActionEventTest(); + try { + mainThread.sleep(sleepTime); + } catch (InterruptedException e) { + if (!isProgInterruption) { + throw e; + } + } + test.dispose(); + if (!isProgInterruption) { + throw new RuntimeException("Timed out after " + sleepTime / 1000 + + " seconds"); + } + } +} diff --git a/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java new file mode 100644 index 00000000000..f1cd8e32a46 --- /dev/null +++ b/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6191390 + * @summary Verify that ActionEvent is received with correct modifiers set. + * @run main ActionEventTest + */ + +import java.awt.AWTException; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +public class ActionEventTest extends Frame { + List list; + Robot robot; + + public ActionEventTest() { + try { + robot = new Robot(); + } catch(AWTException e) { + throw new RuntimeException(e.getMessage()); + } + + list = new List(1, false); + list.add("0"); + add(list); + setSize(400,400); + setLayout(new FlowLayout()); + pack(); + setVisible(true); + robot.waitForIdle(); + } + + void performTest() { + list.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + int md = ae.getModifiers(); + int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK + | ActionEvent.SHIFT_MASK; + + if ((md & expectedMask) != expectedMask) { + + robot.keyRelease(KeyEvent.VK_ALT); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.keyRelease(KeyEvent.VK_CONTROL); + dispose(); + throw new RuntimeException("Action Event modifiers are not" + + " set correctly."); + } + } + }); + + list.select(0); + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_CONTROL); + // Press Enter on list item, to generate action event. + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + robot.keyRelease(KeyEvent.VK_ALT); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + } + + public static void main(String args[]) { + ActionEventTest test = new ActionEventTest(); + test.performTest(); + test.dispose(); + } +} diff --git a/jdk/test/java/awt/MenuBar/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/MenuBar/ActionEventTest/ActionEventTest.java new file mode 100644 index 00000000000..6af94798e31 --- /dev/null +++ b/jdk/test/java/awt/MenuBar/ActionEventTest/ActionEventTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6191390 + * @summary Verify that ActionEvent is received with correct modifiers set. + * @run main/manual ActionEventTest + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public final class ActionEventTest extends Frame { + + MenuBar menuBar; + TextArea instructions; + public static boolean isProgInterruption = false; + static Thread mainThread = null; + static int sleepTime = 300000; + + public ActionEventTest() { + menuBar = new MenuBar(); + Menu menu = new Menu("Menu1"); + MenuItem menuItem = new MenuItem("MenuItem"); + + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + System.out.println("actionPerformed"); + int md = ae.getModifiers(); + int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK + | ActionEvent.SHIFT_MASK; + + isProgInterruption = true; + mainThread.interrupt(); + if ((md & expectedMask) != expectedMask) { + throw new RuntimeException("Action Event modifiers are not" + + " set correctly."); + } + } + }); + menu.add(menuItem); + menuBar.add(menu); + setMenuBar(menuBar); + + instructions = new TextArea(10, 50); + instructions.setText( + " This is a manual test\n" + + " Keep the Alt, Shift & Ctrl Keys pressed while doing next steps\n" + + " Click 'Menu1' Menu from the Menu Bar\n" + + " It will show 'MenuItem'\n" + + " Left mouse Click the 'MenuItem'\n" + + " Test exits automatically after mouse click."); + add(instructions); + + setSize(400, 400); + setVisible(true); + validate(); + } + + + public static void main(final String[] args) throws Exception { + mainThread = Thread.currentThread(); + ActionEventTest test = new ActionEventTest(); + try { + mainThread.sleep(sleepTime); + } catch (InterruptedException e) { + if (!isProgInterruption) { + throw e; + } + } + test.dispose(); + if (!isProgInterruption) { + throw new RuntimeException("Timed out after " + sleepTime / 1000 + + " seconds"); + } + } +} diff --git a/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java new file mode 100644 index 00000000000..7a5f87a38f3 --- /dev/null +++ b/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6191390 + * @summary Verify that ActionEvent is received with correct modifiers set. + * @library ../../../../lib/testlibrary ../ + * @build ExtendedRobot SystemTrayIconHelper + */ + +import java.awt.Image; +import java.awt.TrayIcon; +import java.awt.SystemTray; +import java.awt.Robot; +import java.awt.EventQueue; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; + +public class ActionEventTest { + + Image image; + TrayIcon icon; + Robot robot; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + System.out.println("SystemTray not supported on the platform." + + " Marking the test passed."); + } else { + if (System.getProperty("os.name").toLowerCase().startsWith("win")) { + System.err.println( + "Test can fail on Windows platform\n"+ + "On Windows 7, by default icon hides behind icon pool\n" + + "Due to which test might fail\n" + + "Set \"Right mouse click\" -> " + + "\"Customize notification icons\" -> \"Always show " + + "all icons and notifications on the taskbar\" true " + + "to avoid this problem.\nOR change behavior only for " + + "Java SE tray icon and rerun test."); + } + + ActionEventTest test = new ActionEventTest(); + test.doTest(); + test.clear(); + } + } + + public ActionEventTest() throws Exception { + robot = new Robot(); + EventQueue.invokeAndWait(this::initializeGUI); + } + + private void initializeGUI() { + + icon = new TrayIcon( + new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB), "ti"); + icon.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + int md = ae.getModifiers(); + int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK + | ActionEvent.SHIFT_MASK; + + if ((md & expectedMask) != expectedMask) { + clear(); + throw new RuntimeException("Action Event modifiers are not" + + " set correctly."); + } + } + }); + + try { + SystemTray.getSystemTray().add(icon); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void clear() { + SystemTray.getSystemTray().remove(icon); + } + + void doTest() throws Exception { + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_CONTROL); + + Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon); + if (iconPosition == null) { + throw new RuntimeException("Unable to find the icon location!"); + } + + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.waitForIdle(); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(100); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(100); + robot.waitForIdle(); + robot.keyRelease(KeyEvent.VK_ALT); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.keyRelease(KeyEvent.VK_CONTROL); + } +} From 17344961d2026a3567c5e638cd6eef6a4efb9cda Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Wed, 13 Apr 2016 12:10:42 +0300 Subject: [PATCH 071/222] 8153856: com/sun/jdi/WatchFramePop.sh fails with exit code 1 Fixed sed expression in a test Reviewed-by: sla --- jdk/test/com/sun/jdi/ShellScaffold.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/com/sun/jdi/ShellScaffold.sh b/jdk/test/com/sun/jdi/ShellScaffold.sh index ed5f79e58ac..eb7e6b45351 100644 --- a/jdk/test/com/sun/jdi/ShellScaffold.sh +++ b/jdk/test/com/sun/jdi/ShellScaffold.sh @@ -924,7 +924,7 @@ dojstack() # If jstack exists, so will jps # Show stack traces of jdb and debuggee as a possible debugging aid. jdbCmd=`$jdk/bin/jps -v | $grep $jdbKeyword` - realJdbPid=`echo "$jdbCmd" | sed -e 's@ TTY.*@@'` + realJdbPid=`echo "$jdbCmd" | sed -e 's@ .*@@'` if [ ! -z "$realJdbPid" ] ; then echo "-- jdb process info ----------------------" >&2 echo " $jdbCmd" >&2 From bf3b2fe3608c363bed0e1aa1cefd9d31a73b668e Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Wed, 13 Apr 2016 11:13:14 +0200 Subject: [PATCH 072/222] 8154087: Fix AIX and Linux/ppc64le after the integration of the new hotspot build Reviewed-by: erikj, goetz --- common/autoconf/flags.m4 | 25 +++++------ common/autoconf/generated-configure.sh | 60 +++++++++++++++----------- common/autoconf/platform.m4 | 4 ++ 3 files changed, 52 insertions(+), 37 deletions(-) diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index 5e9fc128843..7789f01450e 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -929,20 +929,21 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], elif test "x$OPENJDK_$1_CPU" = xppc64; then if test "x$OPENJDK_$1_OS" = xlinux; then $2JVM_CFLAGS="[$]$2JVM_CFLAGS -minsert-sched-nops=regroup_exact -mno-multiple -mno-string" - if test "x$OPENJDK_$1_CPU_ENDIAN" = xbig; then - # fixes `relocation truncated to fit' error for gcc 4.1. - $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mminimal-toc" - # Use ppc64 instructions, but schedule for power5 - $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mcpu=powerpc64 -mtune=power5" - else - # Little endian machine uses ELFv2 ABI. - $2JVM_CFLAGS="[$]$2JVM_CFLAGS -DABI_ELFv2" - # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. - $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mcpu=power7 -mtune=power8" - fi + # fixes `relocation truncated to fit' error for gcc 4.1. + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mminimal-toc" + # Use ppc64 instructions, but schedule for power5 + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mcpu=powerpc64 -mtune=power5" elif test "x$OPENJDK_$1_OS" = xaix; then $2JVM_CFLAGS="[$]$2JVM_CFLAGS -qarch=ppc64" - fi + fi + elif test "x$OPENJDK_$1_CPU" = xppc64le; then + if test "x$OPENJDK_$1_OS" = xlinux; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -minsert-sched-nops=regroup_exact -mno-multiple -mno-string" + # Little endian machine uses ELFv2 ABI. + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -DABI_ELFv2" + # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mcpu=power7 -mtune=power8" + fi fi if test "x$OPENJDK_$1_CPU_ENDIAN" = xlittle; then diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index d97c4b4ebc7..632dd15d1b0 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -5056,7 +5056,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1460103573 +DATE_WHEN_GENERATED=1460538705 ############################################################################### # @@ -15448,6 +15448,8 @@ $as_echo "$COMPILE_TYPE" >&6; } HOTSPOT_TARGET_CPU=sparc elif test "x$OPENJDK_TARGET_CPU" = xppc64; then HOTSPOT_TARGET_CPU=ppc_64 + elif test "x$OPENJDK_TARGET_CPU" = xppc64le; then + HOTSPOT_TARGET_CPU=ppc_64 fi @@ -15466,6 +15468,8 @@ $as_echo "$COMPILE_TYPE" >&6; } HOTSPOT_TARGET_CPU_DEFINE=AARCH64 elif test "x$OPENJDK_TARGET_CPU" = xppc64; then HOTSPOT_TARGET_CPU_DEFINE=PPC64 + elif test "x$OPENJDK_TARGET_CPU" = xppc64le; then + HOTSPOT_TARGET_CPU_DEFINE=PPC64 # The cpu defines below are for zero, we don't support them directly. elif test "x$OPENJDK_TARGET_CPU" = xsparc; then @@ -15600,6 +15604,8 @@ $as_echo "$COMPILE_TYPE" >&6; } HOTSPOT_BUILD_CPU=sparc elif test "x$OPENJDK_BUILD_CPU" = xppc64; then HOTSPOT_BUILD_CPU=ppc_64 + elif test "x$OPENJDK_BUILD_CPU" = xppc64le; then + HOTSPOT_BUILD_CPU=ppc_64 fi @@ -15618,6 +15624,8 @@ $as_echo "$COMPILE_TYPE" >&6; } HOTSPOT_BUILD_CPU_DEFINE=AARCH64 elif test "x$OPENJDK_BUILD_CPU" = xppc64; then HOTSPOT_BUILD_CPU_DEFINE=PPC64 + elif test "x$OPENJDK_BUILD_CPU" = xppc64le; then + HOTSPOT_BUILD_CPU_DEFINE=PPC64 # The cpu defines below are for zero, we don't support them directly. elif test "x$OPENJDK_BUILD_CPU" = xsparc; then @@ -49834,20 +49842,21 @@ $as_echo "$supports" >&6; } elif test "x$OPENJDK_TARGET_CPU" = xppc64; then if test "x$OPENJDK_TARGET_OS" = xlinux; then JVM_CFLAGS="$JVM_CFLAGS -minsert-sched-nops=regroup_exact -mno-multiple -mno-string" - if test "x$OPENJDK_TARGET_CPU_ENDIAN" = xbig; then - # fixes `relocation truncated to fit' error for gcc 4.1. - JVM_CFLAGS="$JVM_CFLAGS -mminimal-toc" - # Use ppc64 instructions, but schedule for power5 - JVM_CFLAGS="$JVM_CFLAGS -mcpu=powerpc64 -mtune=power5" - else - # Little endian machine uses ELFv2 ABI. - JVM_CFLAGS="$JVM_CFLAGS -DABI_ELFv2" - # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. - JVM_CFLAGS="$JVM_CFLAGS -mcpu=power7 -mtune=power8" - fi + # fixes `relocation truncated to fit' error for gcc 4.1. + JVM_CFLAGS="$JVM_CFLAGS -mminimal-toc" + # Use ppc64 instructions, but schedule for power5 + JVM_CFLAGS="$JVM_CFLAGS -mcpu=powerpc64 -mtune=power5" elif test "x$OPENJDK_TARGET_OS" = xaix; then JVM_CFLAGS="$JVM_CFLAGS -qarch=ppc64" - fi + fi + elif test "x$OPENJDK_TARGET_CPU" = xppc64le; then + if test "x$OPENJDK_TARGET_OS" = xlinux; then + JVM_CFLAGS="$JVM_CFLAGS -minsert-sched-nops=regroup_exact -mno-multiple -mno-string" + # Little endian machine uses ELFv2 ABI. + JVM_CFLAGS="$JVM_CFLAGS -DABI_ELFv2" + # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. + JVM_CFLAGS="$JVM_CFLAGS -mcpu=power7 -mtune=power8" + fi fi if test "x$OPENJDK_TARGET_CPU_ENDIAN" = xlittle; then @@ -50610,20 +50619,21 @@ $as_echo "$supports" >&6; } elif test "x$OPENJDK_BUILD_CPU" = xppc64; then if test "x$OPENJDK_BUILD_OS" = xlinux; then OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -minsert-sched-nops=regroup_exact -mno-multiple -mno-string" - if test "x$OPENJDK_BUILD_CPU_ENDIAN" = xbig; then - # fixes `relocation truncated to fit' error for gcc 4.1. - OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mminimal-toc" - # Use ppc64 instructions, but schedule for power5 - OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mcpu=powerpc64 -mtune=power5" - else - # Little endian machine uses ELFv2 ABI. - OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DABI_ELFv2" - # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. - OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mcpu=power7 -mtune=power8" - fi + # fixes `relocation truncated to fit' error for gcc 4.1. + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mminimal-toc" + # Use ppc64 instructions, but schedule for power5 + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mcpu=powerpc64 -mtune=power5" elif test "x$OPENJDK_BUILD_OS" = xaix; then OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -qarch=ppc64" - fi + fi + elif test "x$OPENJDK_BUILD_CPU" = xppc64le; then + if test "x$OPENJDK_BUILD_OS" = xlinux; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -minsert-sched-nops=regroup_exact -mno-multiple -mno-string" + # Little endian machine uses ELFv2 ABI. + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DABI_ELFv2" + # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mcpu=power7 -mtune=power8" + fi fi if test "x$OPENJDK_BUILD_CPU_ENDIAN" = xlittle; then diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index 587f80dbcd5..deaf22ed169 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -405,6 +405,8 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], HOTSPOT_$1_CPU=sparc elif test "x$OPENJDK_$1_CPU" = xppc64; then HOTSPOT_$1_CPU=ppc_64 + elif test "x$OPENJDK_$1_CPU" = xppc64le; then + HOTSPOT_$1_CPU=ppc_64 fi AC_SUBST(HOTSPOT_$1_CPU) @@ -423,6 +425,8 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], HOTSPOT_$1_CPU_DEFINE=AARCH64 elif test "x$OPENJDK_$1_CPU" = xppc64; then HOTSPOT_$1_CPU_DEFINE=PPC64 + elif test "x$OPENJDK_$1_CPU" = xppc64le; then + HOTSPOT_$1_CPU_DEFINE=PPC64 # The cpu defines below are for zero, we don't support them directly. elif test "x$OPENJDK_$1_CPU" = xsparc; then From a98a7da445dc5f085a3a530ab7949ea8807e1a42 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Wed, 13 Apr 2016 11:13:15 +0200 Subject: [PATCH 073/222] 8154087: Fix AIX and Linux/ppc64le after the integration of the new hotspot build Reviewed-by: erikj, goetz --- jdk/make/lib/Awt2dLibraries.gmk | 7 +++++++ jdk/make/lib/CoreLibraries.gmk | 1 + jdk/make/lib/NioLibraries.gmk | 1 + 3 files changed, 9 insertions(+) diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk index d6ba6443bf2..b8941c0b105 100644 --- a/jdk/make/lib/Awt2dLibraries.gmk +++ b/jdk/make/lib/Awt2dLibraries.gmk @@ -370,6 +370,7 @@ ifeq ($(findstring $(OPENJDK_TARGET_OS),windows macosx),) OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_XAWT_CFLAGS) \ $(X_CFLAGS), \ + WARNINGS_AS_ERRORS_xlc := false, \ DISABLED_WARNINGS_gcc := type-limits pointer-to-int-cast \ deprecated-declarations unused-result maybe-uninitialized format \ format-security int-to-pointer-cast parentheses, \ @@ -582,6 +583,7 @@ ifeq ($(BUILD_HEADLESS), true) $(CUPS_CFLAGS) \ $(X_CFLAGS) \ $(LIBAWT_HEADLESS_CFLAGS), \ + DISABLED_WARNINGS_xlc := 1506-356, \ DISABLED_WARNINGS_gcc := maybe-uninitialized int-to-pointer-cast, \ DISABLED_WARNINGS_solstudio := E_DECLARATION_IN_CODE \ E_EMPTY_TRANSLATION_UNIT, \ @@ -598,6 +600,10 @@ ifeq ($(BUILD_HEADLESS), true) OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libawt_headless, \ )) + # AIX warning explanation: + # 1506-356 : (W) Compilation unit is empty. + # This happens during the headless build + $(BUILD_LIBAWT_HEADLESS): $(BUILD_LIBAWT) TARGETS += $(BUILD_LIBAWT_HEADLESS) @@ -695,6 +701,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBFONTMANAGER, \ CXXFLAGS := $(CXXFLAGS_JDKLIB) $(LIBFONTMANAGER_CFLAGS), \ OPTIMIZATION := $(LIBFONTMANAGER_OPTIMIZATION), \ CFLAGS_windows = -DCC_NOEX, \ + WARNINGS_AS_ERRORS_xlc := false, \ DISABLED_WARNINGS_gcc := sign-compare int-to-pointer-cast \ type-limits missing-field-initializers, \ DISABLED_WARNINGS_CXX_gcc := reorder delete-non-virtual-dtor strict-overflow \ diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk index bccf46bb824..e4a24e47904 100644 --- a/jdk/make/lib/CoreLibraries.gmk +++ b/jdk/make/lib/CoreLibraries.gmk @@ -146,6 +146,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJAVA, \ $(LIBJAVA_CFLAGS), \ System.c_CFLAGS := $(VERSION_CFLAGS), \ jdk_util.c_CFLAGS := $(VERSION_CFLAGS), \ + WARNINGS_AS_ERRORS_xlc := false, \ DISABLED_WARNINGS_gcc := unused-result, \ DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \ MAPFILE := $(LIBJAVA_MAPFILE), \ diff --git a/jdk/make/lib/NioLibraries.gmk b/jdk/make/lib/NioLibraries.gmk index de2cdea0727..203447c513f 100644 --- a/jdk/make/lib/NioLibraries.gmk +++ b/jdk/make/lib/NioLibraries.gmk @@ -70,6 +70,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBNIO, \ SRC := $(BUILD_LIBNIO_SRC), \ EXCLUDE_FILES := $(BUILD_LIBNIO_EXFILES), \ OPTIMIZATION := HIGH, \ + WARNINGS_AS_ERRORS_xlc := false, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(BUILD_LIBNIO_CFLAGS), \ MAPFILE := $(BUILD_LIBNIO_MAPFILE), \ From 75a63ccb0d1b976e474f29e5ca2fe11cfcd83c76 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 13 Apr 2016 17:04:02 +0530 Subject: [PATCH 074/222] 8147841: [macosx] Updating TrayIcons popup menu does not work on Mac OS X Reviewed-by: serb, ssadetsky --- .../classes/sun/lwawt/macosx/CTrayIcon.java | 21 +- .../UpdatePopupMenu/UpdatePopupMenu.java | 233 ++++++++++++++++++ 2 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 jdk/test/java/awt/TrayIcon/UpdatePopupMenu/UpdatePopupMenu.java diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java index 2d82a2eb1c1..abd092b8be9 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java @@ -98,15 +98,26 @@ public class CTrayIcon extends CFRetainedResource implements TrayIconPeer { private native long nativeCreate(); //invocation from the AWTTrayIcon.m - public long getPopupMenuModel(){ - if(popup == null) { - PopupMenu popupMenu = target.getPopupMenu(); - if (popupMenu != null) { - popup = popupMenu; + public long getPopupMenuModel() { + PopupMenu newPopup = target.getPopupMenu(); + + if (popup == newPopup) { + if (popup == null) { + return 0L; + } + } else { + if (newPopup != null) { + if (popup != null) { + popup.removeNotify(); + popup = newPopup; + } else { + popup = newPopup; + } } else { return 0L; } } + return checkAndCreatePopupPeer().getModel(); } diff --git a/jdk/test/java/awt/TrayIcon/UpdatePopupMenu/UpdatePopupMenu.java b/jdk/test/java/awt/TrayIcon/UpdatePopupMenu/UpdatePopupMenu.java new file mode 100644 index 00000000000..b19dd209f78 --- /dev/null +++ b/jdk/test/java/awt/TrayIcon/UpdatePopupMenu/UpdatePopupMenu.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8147841 + @summary Updating Tray Icon popup menu does not update menu items on Mac OS X + @run main/manual UpdatePopupMenu + */ + +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.PopupMenu; +import java.awt.MenuItem; +import java.awt.Image; +import java.awt.Graphics2D; +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.awt.RenderingHints; +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class UpdatePopupMenu implements ActionListener { + + private static final int imageSize = 32; + private static final int imageInset = 4; + private static GridBagLayout layout; + private static Panel mainControlPanel; + private static Panel resultButtonPanel; + private static TextArea instructionTextArea; + private static Button passButton; + private static Button failButton; + private static Frame mainFrame; + private static Thread mainThread = null; + private static boolean testPassed = false; + private static boolean isInterrupted = false; + private static final int testTimeOut = 300000; + + private Image createSystemTrayIconImage() { + final BufferedImage trayImage = new BufferedImage( + imageSize, + imageSize, + BufferedImage.TYPE_INT_ARGB); + + final Graphics2D imageGraphics = (Graphics2D) trayImage.getGraphics(); + + imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + imageGraphics.setColor(new Color(255, 255, 255, 0)); + imageGraphics.fillRect(0, 0, trayImage.getWidth(), + trayImage.getHeight()); + + imageGraphics.setColor(Color.green); + + int imageWidth = trayImage.getWidth() - 2 * imageInset; + int imageHeight = trayImage.getHeight() - 2 * imageInset; + + imageGraphics.fillOval(imageInset, imageInset, imageWidth, imageHeight); + imageGraphics.setColor(Color.darkGray); + imageGraphics.drawOval(imageInset, imageInset, imageWidth, imageHeight); + + return trayImage; + } + + private PopupMenu createPopupMenu(final TrayIcon trayIcon, + final int menuCount) { + + final PopupMenu trayIconPopupMenu = new PopupMenu(); + + for (int i = 1; i <= menuCount; ++i) { + final MenuItem popupMenuItem = new MenuItem("MenuItem_" + i); + + popupMenuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(final ActionEvent ae) { + trayIcon.setPopupMenu(createPopupMenu(trayIcon, + menuCount + 1)); + } + }); + + trayIconPopupMenu.add(popupMenuItem); + } + + return trayIconPopupMenu; + } + + private void createSystemTrayIcons() { + + final TrayIcon trayIcon = new TrayIcon(createSystemTrayIconImage()); + trayIcon.setImageAutoSize(true); + trayIcon.setToolTip("Update Popup Menu items"); + + try { + trayIcon.setPopupMenu(createPopupMenu(trayIcon, 2)); + SystemTray.getSystemTray().add(trayIcon); + + } catch (AWTException ex) { + throw new RuntimeException("System Tray cration failed"); + } + } + + private void createInstructionUI() { + mainFrame = new Frame("Updating TrayIcon Popup Menu Item Test"); + layout = new GridBagLayout(); + mainControlPanel = new Panel(layout); + resultButtonPanel = new Panel(layout); + + GridBagConstraints gbc = new GridBagConstraints(); + String instructions + = "INSTRUCTIONS:" + + "\n 1. Click on the System Tray Icon" + + "\n 2. Click on any of the displayed Menu items" + + "\n 3. Repeat step 1 and count the number of items in the " + + "Menu" + + "\n 4. The number of items in the Menu should increase by 1" + + "\n 5. Repeating steps 1, 2 and 3 should not break 4th step" + + "\n 6. Click Fail if the 4th step is broken, Otherwise " + + "click Pass "; + + instructionTextArea = new TextArea(); + instructionTextArea.setText(instructions); + instructionTextArea.setEnabled(false); + instructionTextArea.setBackground(Color.white); + + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(instructionTextArea, gbc); + + passButton = new Button("Pass"); + passButton.setName("Pass"); + passButton.addActionListener(this); + + failButton = new Button("Fail"); + failButton.setName("Fail"); + failButton.addActionListener(this); + + gbc.gridx = 0; + gbc.gridy = 0; + resultButtonPanel.add(passButton, gbc); + gbc.gridx = 1; + gbc.gridy = 0; + resultButtonPanel.add(failButton, gbc); + gbc.gridx = 0; + gbc.gridy = 1; + mainControlPanel.add(resultButtonPanel, gbc); + + mainFrame.add(mainControlPanel); + mainFrame.pack(); + mainFrame.setVisible(true); + } + + @Override + public void actionPerformed(ActionEvent ae) { + if (ae.getSource() instanceof Button) { + Button btn = (Button) ae.getSource(); + switch (btn.getName()) { + case "Pass": + testPassed = true; + isInterrupted = true; + mainThread.interrupt(); + break; + + case "Fail": + testPassed = false; + isInterrupted = true; + mainThread.interrupt(); + break; + } + } + } + + private static void cleanUp() { + mainFrame.dispose(); + } + + public static void main(final String[] args) throws Exception { + if (SystemTray.isSupported()) { + + UpdatePopupMenu updatePopupMenu = new UpdatePopupMenu(); + updatePopupMenu.createInstructionUI(); + updatePopupMenu.createSystemTrayIcons(); + + mainThread = Thread.currentThread(); + try { + mainThread.sleep(testTimeOut); + } catch (InterruptedException ex) { + if (!testPassed) { + throw new RuntimeException("Updating TrayIcon popup menu" + + " items FAILED"); + } + } finally { + cleanUp(); + } + + if (!isInterrupted) { + throw new RuntimeException("Test Timed out after " + + testTimeOut / 1000 + " seconds"); + } + + } else { + System.out.println("System Tray is not supported on this platform"); + } + } +} From b7b4dfdc09a0bcdcef9491753f79d7819b424fc8 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Thu, 14 Apr 2016 13:07:35 +0300 Subject: [PATCH 075/222] 8146035: Windows - With LCD antialiasing, some glyphs are not rendered correctly Reviewed-by: serb, prr --- .../windows/native/libfontmanager/lcdglyph.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.desktop/windows/native/libfontmanager/lcdglyph.c b/jdk/src/java.desktop/windows/native/libfontmanager/lcdglyph.c index 05f4aae9d82..d940e8cb468 100644 --- a/jdk/src/java.desktop/windows/native/libfontmanager/lcdglyph.c +++ b/jdk/src/java.desktop/windows/native/libfontmanager/lcdglyph.c @@ -157,6 +157,9 @@ JNIEXPORT jboolean JNICALL if (hBitmap != 0) { \ DeleteObject(hBitmap); \ } \ + if (tmpBitmap != 0) { \ + DeleteObject(tmpBitmap); \ + } \ if (dibImage != NULL) { \ free(dibImage); \ } \ @@ -196,6 +199,7 @@ Java_sun_font_FileFontStrike__1getGlyphImageFromWindows int bmWidth, bmHeight; int x, y; HBITMAP hBitmap = NULL, hOrigBM; + HBITMAP tmpBitmap = NULL; int gamma, orient; HWND hWnd = NULL; @@ -250,6 +254,12 @@ Java_sun_font_FileFontStrike__1getGlyphImageFromWindows } oldFont = SelectObject(hMemoryDC, hFont); + tmpBitmap = CreateCompatibleBitmap(hDesktopDC, 1, 1); + if (tmpBitmap == NULL) { + FREE_AND_RETURN; + } + hOrigBM = (HBITMAP)SelectObject(hMemoryDC, tmpBitmap); + memset(&textMetric, 0, sizeof(TEXTMETRIC)); err = GetTextMetrics(hMemoryDC, &textMetric); if (err == 0) { @@ -334,7 +344,7 @@ Java_sun_font_FileFontStrike__1getGlyphImageFromWindows if (hBitmap == NULL) { FREE_AND_RETURN; } - hOrigBM = (HBITMAP)SelectObject(hMemoryDC, hBitmap); + SelectObject(hMemoryDC, hBitmap); /* Fill in black */ rect.left = 0; @@ -478,6 +488,7 @@ Java_sun_font_FileFontStrike__1getGlyphImageFromWindows ReleaseDC(hWnd, hDesktopDC); DeleteObject(hMemoryDC); DeleteObject(hBitmap); + DeleteObject(tmpBitmap); return ptr_to_jlong(glyphInfo); } From 26e64bbd263d7ba37c5f0766104115c1248f65f1 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Thu, 14 Apr 2016 20:32:50 +0300 Subject: [PATCH 076/222] 8153351: GTK Menu's have no border Reviewed-by: alexsch, serb --- .../sun/java/swing/plaf/gtk/GTKPainter.java | 41 +++++++++++++++---- .../com/sun/java/swing/plaf/gtk/GTKStyle.java | 15 +++++++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java index ad61aca85f1..ecd319a337f 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -576,12 +576,11 @@ class GTKPainter extends SynthPainter { ShadowType.OUT, "menu", x, y, w, h); GTKStyle style = (GTKStyle)context.getStyle(); - int xThickness = style.getXThickness(); - int yThickness = style.getYThickness(); + Insets insets = style.getInsets(context, null); ENGINE.paintBackground(g, context, id, gtkState, - style.getGTKColor(context, gtkState, GTKColorType.BACKGROUND), - x + xThickness, y + yThickness, - w - xThickness - xThickness, h - yThickness - yThickness); + style.getGTKColor(context, gtkState, GTKColorType.BACKGROUND), + x + insets.left, y + insets.top, w - insets.left - insets.right, + h - insets.top - insets.bottom); ENGINE.finishPainting(); } } @@ -640,6 +639,34 @@ class GTKPainter extends SynthPainter { int state = context.getComponentState(); JComponent c = context.getComponent(); + GTKStyle style = (GTKStyle) context.getStyle(); + String detail; + // wide-separators are painted using box not line + if (style.getClassSpecificBoolValue(context, + "wide-separators", false)) { + Insets insets = c.getInsets(); + x += insets.left; + y += insets.top; + if (orientation == JSeparator.HORIZONTAL) { + w -= (insets.left + insets.right); + detail = "hseparator"; + } else { + h -= (insets.top + insets.bottom); + detail = "vseparator"; + } + synchronized (UNIXToolkit.GTK_LOCK) { + if (! ENGINE.paintCachedImage(g, x, y, w, h, id, state, + detail, orientation)) { + ENGINE.startPainting(g, x, y, w, h, id, state, + detail, orientation); + ENGINE.paintBox(g, context, id, state, + ShadowType.ETCHED_OUT, detail, x, y, w, h); + ENGINE.finishPainting(); + } + } + return; + } + /* * Note: In theory, the style's x/y thickness values would determine * the width of the separator content. In practice, however, some @@ -650,7 +677,6 @@ class GTKPainter extends SynthPainter { * the w/h values below too much, so that the full thickness of the * rendered line will be captured by our image caching code. */ - String detail; if (c instanceof JToolBar.Separator) { /* * GTK renders toolbar separators differently in that an @@ -678,7 +704,6 @@ class GTKPainter extends SynthPainter { float pct = 0.2f; JToolBar.Separator sep = (JToolBar.Separator)c; Dimension size = sep.getSeparatorSize(); - GTKStyle style = (GTKStyle)context.getStyle(); if (orientation == JSeparator.HORIZONTAL) { x += (int)(w * pct); w -= (int)(w * pct * 2); diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java index 4fa44c758e5..fe54752cef6 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java @@ -776,6 +776,15 @@ class GTKStyle extends SynthStyle implements GTKConstants { } else if (key == "Separator.thickness") { JSeparator sep = (JSeparator)context.getComponent(); + if (getClassSpecificBoolValue(context, "wide-separators", false)) { + if (sep.getOrientation() == JSeparator.HORIZONTAL) { + return getClassSpecificIntValue(context, + "separator-height", 0); + } else { + return getClassSpecificIntValue(context, + "separator-width", 0); + } + } if (sep.getOrientation() == JSeparator.HORIZONTAL) { return getYThickness(); } else { @@ -783,6 +792,12 @@ class GTKStyle extends SynthStyle implements GTKConstants { } } else if (key == "ToolBar.separatorSize") { + if (getClassSpecificBoolValue(context, "wide-separators", false)) { + return new DimensionUIResource( + getClassSpecificIntValue(context, "separator-width", 2), + getClassSpecificIntValue(context, "separator-height", 2) + ); + } int size = getClassSpecificIntValue(WidgetType.TOOL_BAR, "space-size", 12); return new DimensionUIResource(size, size); From 524efbad7966199bd1c55d9ac3198209dfa7a115 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 14 Apr 2016 12:36:14 -0700 Subject: [PATCH 077/222] 8134986: Incorrect use of ConcurrentHashMap.contains in SunFontManager.java Reviewed-by: serb, jgodinez --- jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java index 19200c8282b..6ac092ed32e 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java +++ b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java @@ -1843,7 +1843,7 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { private PhysicalFont registerFontFile(String file) { if (new File(file).isAbsolute() && - !registeredFonts.contains(file)) { + !registeredFonts.containsKey(file)) { int fontFormat = FONTFORMAT_NONE; int fontRank = Font2D.UNKNOWN_RANK; if (ttFilter.accept(null, file)) { From 0d5a231133543ae73bbeeed1acc029a76200b5a9 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 15 Apr 2016 11:45:11 +0530 Subject: [PATCH 078/222] 6921664: The number of copies and the job name are not passed to a 3rd party PrintService Reviewed-by: prr, jdv --- .../classes/sun/print/RasterPrinterJob.java | 2 + .../awt/print/PrinterJob/DummyPrintTest.java | 247 ++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 jdk/test/java/awt/print/PrinterJob/DummyPrintTest.java diff --git a/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index b5d8f0daa8f..638e01488e6 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -1388,6 +1388,8 @@ public abstract class RasterPrinterJob extends PrinterJob { Doc doc = new PageableDoc(getPageable()); if (attributes == null) { attributes = new HashPrintRequestAttributeSet(); + attributes.add(new Copies(getCopies())); + attributes.add(new JobName(getJobName(), null)); } try { job.print(doc, attributes); diff --git a/jdk/test/java/awt/print/PrinterJob/DummyPrintTest.java b/jdk/test/java/awt/print/PrinterJob/DummyPrintTest.java new file mode 100644 index 00000000000..43881d5ca9f --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/DummyPrintTest.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6921664 + * @summary Verifies number of copies and the job name are passed to a + * 3rd party PrintService. + * @run main DummyPrintTest + */ +import java.awt.Graphics; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.util.HashSet; +import java.util.Set; +import javax.print.Doc; +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.PrintException; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.ServiceUIFactory; +import javax.print.attribute.Attribute; +import javax.print.attribute.AttributeSet; +import javax.print.attribute.HashPrintJobAttributeSet; +import javax.print.attribute.HashPrintServiceAttributeSet; +import javax.print.attribute.PrintJobAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.PrintServiceAttribute; +import javax.print.attribute.PrintServiceAttributeSet; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.PrinterName; +import javax.print.attribute.standard.PrinterState; +import javax.print.event.PrintJobAttributeListener; +import javax.print.event.PrintJobListener; +import javax.print.event.PrintServiceAttributeListener; + + +public class DummyPrintTest { + + public static void main(String[] args) throws Exception { + // register custom print service implementation + String printerName = "myDummyPrintService"; + PrintServiceLookup.registerService(new DummyPrintService(printerName)); + // calling third party print logic + thirdPartyPrintLogic(printerName); + } + + static void thirdPartyPrintLogic(String printerName) throws Exception { + PrinterJob printerjob = PrinterJob.getPrinterJob(); + printerjob.setCopies(2); + printerjob.setJobName("myJobName"); + printerjob.setPrintable(new DummyPrintable()); + for (PrintService printService : PrinterJob.lookupPrintServices()) { + System.out.println("check printer name of service " + printService); + if (printerName.equals(printService.getName())) { + System.out.println("correct printer service do print..."); + printerjob.setPrintService(printService); + printerjob.print(); + break; + } + } + } +} + +class DummyPrintService implements PrintService { + private final String _name; + private final Set _supportedFlavors; + private final PrintServiceAttributeSet _printServiceAttributeSet; + + public DummyPrintService(String name) { + _name = name; + _supportedFlavors = new HashSet(); + _supportedFlavors.add(DocFlavor.SERVICE_FORMATTED.PAGEABLE); + _supportedFlavors.add(DocFlavor.SERVICE_FORMATTED.PRINTABLE); + _printServiceAttributeSet = new HashPrintServiceAttributeSet(); + _printServiceAttributeSet.add(new PrinterName(name, null)); + _printServiceAttributeSet.add(PrinterState.IDLE); + } + + @Override + public String toString() { + return "Dummy Printer : " + getName(); + } + + @Override + public String getName() { + return _name; + } + + @Override + public DocPrintJob createPrintJob() { + return new DummyDocPrintJob(this); + } + + @Override + public boolean isDocFlavorSupported(DocFlavor flavor) { + return _supportedFlavors.contains(flavor); + } + + @Override + public T getAttribute(Class category) { + return category.cast(_printServiceAttributeSet.get(category)); + } + + @Override + public PrintServiceAttributeSet getAttributes() { + return _printServiceAttributeSet; + } + + @Override + public DocFlavor[] getSupportedDocFlavors() { + return _supportedFlavors.toArray(new DocFlavor[_supportedFlavors.size()]); + } + + @Override + public Object getDefaultAttributeValue(Class category) { + return null; + } + + @Override + public ServiceUIFactory getServiceUIFactory() { + return null; + } + + @Override + public Class[] getSupportedAttributeCategories() { + return null; + } + + @Override + public Object getSupportedAttributeValues(Class category, + DocFlavor flavor, AttributeSet attributes) { + return null; + } + + @Override + public AttributeSet getUnsupportedAttributes(DocFlavor flavor, + AttributeSet attributes) { + return null; + } + + @Override + public boolean isAttributeCategorySupported(Class category) { + return false; + } + + @Override + public boolean isAttributeValueSupported(Attribute attrval, + DocFlavor flavor, + AttributeSet attributes) { + return false; + } + + @Override + public void addPrintServiceAttributeListener(PrintServiceAttributeListener listener) { + } + + @Override + public void removePrintServiceAttributeListener(PrintServiceAttributeListener listener) { + } +} + +class DummyDocPrintJob implements DocPrintJob { + private static int _counter; + private final PrintService _printService; + private final PrintJobAttributeSet _printJobAttributeSet; + + public DummyDocPrintJob(PrintService printService) { + _counter++; + _printService = printService; + _printJobAttributeSet = new HashPrintJobAttributeSet(); + } + + @Override + public PrintService getPrintService() { + return _printService; + } + + @Override + public PrintJobAttributeSet getAttributes() { + return _printJobAttributeSet; + } + + @Override + public void addPrintJobAttributeListener(PrintJobAttributeListener listener, + PrintJobAttributeSet printJobAttributeSet) { + } + + @Override + public void removePrintJobAttributeListener(PrintJobAttributeListener listener) { + } + + @Override + public void addPrintJobListener(PrintJobListener listener) { + } + + @Override + public void removePrintJobListener(PrintJobListener listener) { + } + + @Override + public void print(Doc doc, + PrintRequestAttributeSet printRequestAttributeSet) + throws PrintException { + System.out.println("job name: " + printRequestAttributeSet.get(JobName.class)); + System.out.println("copies: " + printRequestAttributeSet.get(Copies.class)); + if(printRequestAttributeSet.get(JobName.class) == null || + printRequestAttributeSet.get(Copies.class) == null) { + throw new RuntimeException("Copies and JobName is not passed correctly"); + } + } +} + +class DummyPrintable implements Printable { + @Override + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) + throws PrinterException { + if (pageIndex == 0) { + return Printable.PAGE_EXISTS; + } else { + return Printable.NO_SUCH_PAGE; + } + } +} From 13ab7793b822ea6966227cc4c02f827126f4bd85 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 15 Apr 2016 11:48:08 +0530 Subject: [PATCH 079/222] 6801613: Cross-platform pageDialog and printDialog top margin entry broken Reviewed-by: prr, jdv --- .../classes/sun/print/ServiceDialog.java | 4 +- .../PrinterJob/PageDialogMarginTest.java | 92 +++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/awt/print/PrinterJob/PageDialogMarginTest.java diff --git a/jdk/src/java.desktop/share/classes/sun/print/ServiceDialog.java b/jdk/src/java.desktop/share/classes/sun/print/ServiceDialog.java index f4694100cd2..615304c75f4 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/ServiceDialog.java +++ b/jdk/src/java.desktop/share/classes/sun/print/ServiceDialog.java @@ -1422,13 +1422,13 @@ public class ServiceDialog extends JDialog implements ActionListener { topMargin.addActionListener(this); topMargin.getAccessibleContext().setAccessibleName( getMsg("label.topmargin")); - topMargin = new JFormattedTextField(nf); + bottomMargin = new JFormattedTextField(nf); bottomMargin.addFocusListener(this); bottomMargin.addActionListener(this); bottomMargin.getAccessibleContext().setAccessibleName( getMsg("label.bottommargin")); - topMargin = new JFormattedTextField(nf); + c.gridwidth = GridBagConstraints.RELATIVE; lblLeft = new JLabel(getMsg("label.leftmargin") + " " + unitsMsg, JLabel.LEADING); diff --git a/jdk/test/java/awt/print/PrinterJob/PageDialogMarginTest.java b/jdk/test/java/awt/print/PrinterJob/PageDialogMarginTest.java new file mode 100644 index 00000000000..3efc1125049 --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/PageDialogMarginTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6801613 + * @summary Verifies if cross-platform pageDialog and printDialog top margin + * entry is working + * @run main/manual PageDialogMarginTest + */ +import java.awt.Component; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.MediaPrintableArea; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +public class PageDialogMarginTest { + + public static void main(String args[]) throws Exception { + String[] instructions + = { + "Page Dialog will be shown.", + "Change top(in) margin value from 1.0 to 2.0", + "Then select OK." + }; + SwingUtilities.invokeAndWait(() -> { + JOptionPane.showMessageDialog((Component) null, + instructions, "Instructions", + JOptionPane.INFORMATION_MESSAGE); + }); + PrinterJob pj = PrinterJob.getPrinterJob(); + try { + HashPrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); + PageFormat pf; + pf = pj.pageDialog(aset); + double left = pf.getImageableX(); + double top = pf.getImageableY(); + System.out.println("pageDialog - left/top from pageFormat: " + left / 72 + + " " + top / 72); + System.out.println("pageDialog - left/top from attribute set: " + + getPrintableXFromASet(aset) + " " + + getPrintableYFromASet(aset)); + if (top / 72 != 2.0f || getPrintableYFromASet(aset) != 2.0f) { + throw new RuntimeException("Top margin value not updated"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + static double getPrintableXFromASet(PrintRequestAttributeSet aset) { + try { + return ((MediaPrintableArea) aset.get( + MediaPrintableArea.class)).getX(MediaPrintableArea.INCH); + } catch (Exception e) { + return -1.0; + } + } + + static double getPrintableYFromASet(PrintRequestAttributeSet aset) { + try { + return ((MediaPrintableArea) aset.get( + MediaPrintableArea.class)).getY(MediaPrintableArea.INCH); + } catch (Exception e) { + return -1.0; + } + } + +} From d22bbd1a01922ed98db276879db908235e9fe036 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 15 Apr 2016 11:52:23 +0530 Subject: [PATCH 080/222] 8154057: [macosx] getPrintJob doesn't throw NPE if Frame is null AND type is COMMON Reviewed-by: prr, jdv --- .../macosx/classes/sun/lwawt/LWToolkit.java | 4 ++ jdk/test/java/awt/PrintJob/NullFrameTest.java | 48 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 jdk/test/java/awt/PrintJob/NullFrameTest.java diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java index b7262a5a402..daa02981c27 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java @@ -404,6 +404,10 @@ public abstract class LWToolkit extends SunToolkit implements Runnable { public final PrintJob getPrintJob(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) { + if (frame == null) { + throw new NullPointerException("frame must not be null"); + } + if (GraphicsEnvironment.isHeadless()) { throw new IllegalArgumentException(); } diff --git a/jdk/test/java/awt/PrintJob/NullFrameTest.java b/jdk/test/java/awt/PrintJob/NullFrameTest.java new file mode 100644 index 00000000000..a6de7e5b7fc --- /dev/null +++ b/jdk/test/java/awt/PrintJob/NullFrameTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8154057 + * @summary getPrintJob doesn't throw NPE if frame is null + * @run main NullFrameTest + */ +import java.awt.JobAttributes; +import java.awt.Toolkit; + +public class NullFrameTest { + public static void main(String[] args) { + JobAttributes ja = new JobAttributes(); + ja.setDialog(JobAttributes.DialogType.COMMON); + boolean npeThrown = false; + try { + Toolkit.getDefaultToolkit().getPrintJob(null, + "test Printing", ja, null); + } catch (NullPointerException ex) { + npeThrown = true; + } + if (!npeThrown) { + throw + new RuntimeException("getPrintJob didn't throw NPE for null Frame"); + } + } +} From eca0d89af65e2c9291da6880f1a5d7c610996eaf Mon Sep 17 00:00:00 2001 From: Abdul Kolarkunnu Date: Fri, 15 Apr 2016 12:00:37 +0530 Subject: [PATCH 081/222] 8025430: [TEST_BUG] javax/swing/JEditorPane/5076514/bug5076514.java failed since jdk8b108 Reviewed-by: serb, psadhukhan --- .../swing/JEditorPane/5076514/bug5076514.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 jdk/test/javax/swing/JEditorPane/5076514/bug5076514.java diff --git a/jdk/test/javax/swing/JEditorPane/5076514/bug5076514.java b/jdk/test/javax/swing/JEditorPane/5076514/bug5076514.java new file mode 100644 index 00000000000..fc411722def --- /dev/null +++ b/jdk/test/javax/swing/JEditorPane/5076514/bug5076514.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 5076514 8025430 + @summary Tests if SecurityManager.checkPermission() + used for clipboard access with permission 'accessClipboard' + @run main bug5076514 +*/ + +import java.security.Permission; +import javax.swing.JEditorPane; + +public class bug5076514 { + private final static String ACCESS_CLIPBOARD = "accessClipboard"; + private static boolean isCheckPermissionCalled = false; + + public static void main(String[] args) { + System.setSecurityManager(new MySecurityManager()); + JEditorPane editor = new JEditorPane(); + editor.copy(); + if (!isCheckPermissionCalled) { + throw new RuntimeException("JEditorPane's clipboard operations " + + "didn't call SecurityManager.checkPermission() with " + + "permission 'accessClipboard' when there is a security" + + " manager installed"); + } + } + + private static class MySecurityManager extends SecurityManager { + @Override + public void checkPermission(Permission perm) { + if (ACCESS_CLIPBOARD.equals(perm.getName())) { + isCheckPermissionCalled = true; + } + } + } +} From 40685b42712164d01e4ac7a59da0a91260e6e806 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Fri, 15 Apr 2016 09:46:31 +0300 Subject: [PATCH 082/222] 8080395: consider making sun.awt.CausedFocusEvent functionality public Reviewed-by: alexsch, prr --- .../classes/sun/lwawt/LWComponentPeer.java | 6 +- .../sun/lwawt/LWLightweightFramePeer.java | 6 +- .../classes/sun/lwawt/LWWindowPeer.java | 10 +- .../classes/sun/lwawt/PlatformWindow.java | 6 +- .../classes/sun/lwawt/macosx/CFileDialog.java | 4 +- .../lwawt/macosx/CPlatformEmbeddedFrame.java | 9 +- .../sun/lwawt/macosx/CPlatformLWWindow.java | 6 +- .../sun/lwawt/macosx/CPlatformWindow.java | 6 +- .../macosx/CViewPlatformEmbeddedFrame.java | 4 +- .../share/classes/java/awt/Component.java | 31 ++- .../share/classes/java/awt/Container.java | 5 +- .../java/awt/DefaultKeyboardFocusManager.java | 27 +-- .../java/awt/KeyboardFocusManager.java | 49 ++-- .../share/classes/java/awt/Window.java | 5 +- .../classes/java/awt/event/FocusEvent.java | 184 ++++++++++++-- .../classes/java/awt/peer/ComponentPeer.java | 6 +- .../share/classes/javax/swing/JComponent.java | 4 +- .../share/classes/sun/awt/AWTAccessor.java | 7 +- .../classes/sun/awt/CausedFocusEvent.java | 112 ++++++--- .../sun/awt/KeyboardFocusManagerPeerImpl.java | 16 +- .../classes/sun/awt/NullComponentPeer.java | 6 +- .../sun/awt/RequestFocusController.java | 5 +- .../classes/sun/awt/X11/XComponentPeer.java | 6 +- .../classes/sun/awt/X11/XEmbedCanvasPeer.java | 13 +- .../sun/awt/X11/XEmbedChildProxyPeer.java | 4 +- .../awt/X11/XKeyboardFocusManagerPeer.java | 6 +- .../classes/sun/awt/X11/XTextAreaPeer.java | 9 +- .../classes/sun/awt/X11/XTextFieldPeer.java | 9 +- .../sun/awt/windows/WComponentPeer.java | 7 +- .../sun/awt/windows/WFileDialogPeer.java | 6 +- .../windows/WKeyboardFocusManagerPeer.java | 6 +- .../sun/awt/windows/WPrintDialogPeer.java | 6 +- .../classes/sun/awt/windows/WWindowPeer.java | 6 +- .../java/awt/Focus/Cause/FocusCauseTest.java | 224 ++++++++++++++++++ 34 files changed, 617 insertions(+), 199 deletions(-) create mode 100644 jdk/test/java/awt/Focus/Cause/FocusCauseTest.java diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java index d0a3f65ed58..a024da398b5 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -903,7 +903,7 @@ public abstract class LWComponentPeer @Override public boolean requestFocus(Component lightweightChild, boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("lightweightChild=" + lightweightChild + ", temporary=" + temporary + @@ -1278,7 +1278,7 @@ public abstract class LWComponentPeer assert (e.getSource() == target); if (!target.isFocusOwner() && LWKeyboardFocusManagerPeer.shouldFocusOnClick(target)) { - LWKeyboardFocusManagerPeer.requestFocusFor(target, CausedFocusEvent.Cause.MOUSE_EVENT); + LWKeyboardFocusManagerPeer.requestFocusFor(target, FocusEvent.Cause.MOUSE_EVENT); } } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java index 4491b7c9c05..8205956b649 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,8 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; import java.awt.dnd.DropTarget; +import java.awt.event.FocusEvent; -import sun.awt.CausedFocusEvent; import sun.awt.LightweightFrame; import sun.swing.JLightweightFrame; import sun.swing.SwingAccessor; @@ -60,7 +60,7 @@ public class LWLightweightFramePeer extends LWWindowPeer { } @Override - public boolean requestWindowFocus(CausedFocusEvent.Cause cause) { + public boolean requestWindowFocus(FocusEvent.Cause cause) { if (!focusAllowedFor()) { return false; } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java index fabc2a21ba1..820dc1af2a0 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,14 +256,14 @@ public class LWWindowPeer if (!getTarget().isAutoRequestFocus()) { return; } else { - requestWindowFocus(CausedFocusEvent.Cause.ACTIVATION); + requestWindowFocus(FocusEvent.Cause.ACTIVATION); } // Focus the owner in case this window is focused. } else if (kfmPeer.getCurrentFocusedWindow() == getTarget()) { // Transfer focus to the owner. LWWindowPeer owner = getOwnerFrameDialog(LWWindowPeer.this); if (owner != null) { - owner.requestWindowFocus(CausedFocusEvent.Cause.ACTIVATION); + owner.requestWindowFocus(FocusEvent.Cause.ACTIVATION); } } } @@ -848,7 +848,7 @@ public class LWWindowPeer // 2. An active but not focused owner frame/dialog is clicked. // The mouse event then will trigger a focus request "in window" to the component, so the window // should gain focus before. - requestWindowFocus(CausedFocusEvent.Cause.MOUSE_EVENT); + requestWindowFocus(FocusEvent.Cause.MOUSE_EVENT); mouseDownTarget[targetIdx] = targetPeer; } else if (id == MouseEvent.MOUSE_DRAGGED) { @@ -1199,7 +1199,7 @@ public class LWWindowPeer * Requests platform to set native focus on a frame/dialog. * In case of a simple window, triggers appropriate java focus change. */ - public boolean requestWindowFocus(CausedFocusEvent.Cause cause) { + public boolean requestWindowFocus(FocusEvent.Cause cause) { if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { focusLog.fine("requesting native focus to " + this); } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java index 06bc5f48a83..81134ef48c4 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * 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,8 +26,8 @@ package sun.lwawt; import java.awt.*; +import java.awt.event.FocusEvent; -import sun.awt.CausedFocusEvent; import sun.java2d.SurfaceData; // TODO Is it worth to generify this interface, like that: @@ -114,7 +114,7 @@ public interface PlatformWindow { public void updateFocusableWindowState(); - public boolean rejectFocusRequest(CausedFocusEvent.Cause cause); + public boolean rejectFocusRequest(FocusEvent.Cause cause); public boolean requestWindowFocus(); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java index 34651baba70..e232541c4e3 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,7 @@ package sun.lwawt.macosx; import java.awt.*; +import java.awt.event.FocusEvent.Cause; import java.awt.peer.*; import java.awt.BufferCapabilities.FlipContents; import java.awt.event.*; @@ -34,7 +35,6 @@ import java.security.AccessController; import java.util.List; import java.io.*; -import sun.awt.CausedFocusEvent.Cause; import sun.awt.AWTAccessor; import sun.java2d.pipe.Region; import sun.security.action.GetBooleanAction; diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java index f6ab6bbb4ad..b2e7466b817 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,8 @@ package sun.lwawt.macosx; import java.awt.*; -import sun.awt.CausedFocusEvent; +import java.awt.event.FocusEvent; + import sun.java2d.SurfaceData; import sun.java2d.opengl.CGLLayer; import sun.lwawt.LWWindowPeer; @@ -133,9 +134,9 @@ public class CPlatformEmbeddedFrame implements PlatformWindow { public void updateFocusableWindowState() {} @Override - public boolean rejectFocusRequest(CausedFocusEvent.Cause cause) { + public boolean rejectFocusRequest(FocusEvent.Cause cause) { // Cross-app activation requests are not allowed. - if (cause != CausedFocusEvent.Cause.MOUSE_EVENT && + if (cause != FocusEvent.Cause.MOUSE_EVENT && !target.isParentWindowActive()) { focusLogger.fine("the embedder is inactive, so the request is rejected"); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java index 0d9f9744c41..71bb436dff3 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import java.awt.Rectangle; import java.awt.Window; import sun.awt.CGraphicsDevice; import sun.awt.CGraphicsEnvironment; -import sun.awt.CausedFocusEvent; +import java.awt.event.FocusEvent; import sun.awt.LightweightFrame; import sun.java2d.SurfaceData; import sun.lwawt.LWLightweightFramePeer; @@ -134,7 +134,7 @@ public class CPlatformLWWindow extends CPlatformWindow { } @Override - public boolean rejectFocusRequest(CausedFocusEvent.Cause cause) { + public boolean rejectFocusRequest(FocusEvent.Cause cause) { return false; } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index a9214b45ba7..835f01a5eca 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -706,9 +706,9 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo } @Override - public boolean rejectFocusRequest(CausedFocusEvent.Cause cause) { + public boolean rejectFocusRequest(FocusEvent.Cause cause) { // Cross-app activation requests are not allowed. - if (cause != CausedFocusEvent.Cause.MOUSE_EVENT && + if (cause != FocusEvent.Cause.MOUSE_EVENT && !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive()) { focusLogger.fine("the app is inactive, so the request is rejected"); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java index 1c11789713f..e577f286a91 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import java.awt.Insets; import java.awt.MenuBar; import java.awt.Point; import java.awt.Window; -import sun.awt.CausedFocusEvent.Cause; +import java.awt.event.FocusEvent.Cause; import sun.java2d.SurfaceData; import sun.lwawt.LWWindowPeer; import sun.lwawt.PlatformWindow; diff --git a/jdk/src/java.desktop/share/classes/java/awt/Component.java b/jdk/src/java.desktop/share/classes/java/awt/Component.java index a01b9065c36..b2b51e08559 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Component.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,6 @@ import sun.awt.AWTAccessor; import sun.awt.ConstrainableGraphics; import sun.awt.SubRegionShowable; import sun.awt.SunToolkit; -import sun.awt.CausedFocusEvent; import sun.awt.EmbeddedFrame; import sun.awt.dnd.SunDropTargetEvent; import sun.awt.im.CompositionArea; @@ -878,7 +877,7 @@ public abstract class Component implements ImageObserver, MenuContainer, { comp.setGraphicsConfiguration(gc); } - public boolean requestFocus(Component comp, CausedFocusEvent.Cause cause) { + public boolean requestFocus(Component comp, FocusEvent.Cause cause) { return comp.requestFocus(cause); } public boolean canBeFocusOwner(Component comp) { @@ -7538,7 +7537,7 @@ public abstract class Component implements ImageObserver, MenuContainer, requestFocusHelper(false, true); } - boolean requestFocus(CausedFocusEvent.Cause cause) { + boolean requestFocus(FocusEvent.Cause cause) { return requestFocusHelper(false, true, cause); } @@ -7605,7 +7604,7 @@ public abstract class Component implements ImageObserver, MenuContainer, return requestFocusHelper(temporary, true); } - boolean requestFocus(boolean temporary, CausedFocusEvent.Cause cause) { + boolean requestFocus(boolean temporary, FocusEvent.Cause cause) { return requestFocusHelper(temporary, true, cause); } /** @@ -7656,7 +7655,7 @@ public abstract class Component implements ImageObserver, MenuContainer, return requestFocusHelper(false, false); } - boolean requestFocusInWindow(CausedFocusEvent.Cause cause) { + boolean requestFocusInWindow(FocusEvent.Cause cause) { return requestFocusHelper(false, false, cause); } @@ -7721,18 +7720,18 @@ public abstract class Component implements ImageObserver, MenuContainer, return requestFocusHelper(temporary, false); } - boolean requestFocusInWindow(boolean temporary, CausedFocusEvent.Cause cause) { + boolean requestFocusInWindow(boolean temporary, FocusEvent.Cause cause) { return requestFocusHelper(temporary, false, cause); } final boolean requestFocusHelper(boolean temporary, boolean focusedWindowChangeAllowed) { - return requestFocusHelper(temporary, focusedWindowChangeAllowed, CausedFocusEvent.Cause.UNKNOWN); + return requestFocusHelper(temporary, focusedWindowChangeAllowed, FocusEvent.Cause.UNKNOWN); } final boolean requestFocusHelper(boolean temporary, boolean focusedWindowChangeAllowed, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { // 1) Check if the event being dispatched is a system-generated mouse event. AWTEvent currentEvent = EventQueue.getCurrentEvent(); @@ -7820,7 +7819,7 @@ public abstract class Component implements ImageObserver, MenuContainer, private boolean isRequestFocusAccepted(boolean temporary, boolean focusedWindowChangeAllowed, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { if (!isFocusable() || !isVisible()) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { @@ -7867,7 +7866,7 @@ public abstract class Component implements ImageObserver, MenuContainer, return true; } - if (CausedFocusEvent.Cause.ACTIVATION == cause) { + if (FocusEvent.Cause.ACTIVATION == cause) { // we shouldn't call RequestFocusController in case we are // in activation. We do request focus on component which // has got temporary focus lost and then on component which is @@ -7899,7 +7898,7 @@ public abstract class Component implements ImageObserver, MenuContainer, private static class DummyRequestFocusController implements RequestFocusController { public boolean acceptRequestFocus(Component from, Component to, boolean temporary, boolean focusedWindowChangeAllowed, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { return true; } @@ -7983,7 +7982,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Component toFocus = getNextFocusCandidate(); boolean res = false; if (toFocus != null && !toFocus.isFocusOwner() && toFocus != this) { - res = toFocus.requestFocusInWindow(CausedFocusEvent.Cause.TRAVERSAL_FORWARD); + res = toFocus.requestFocusInWindow(FocusEvent.Cause.TRAVERSAL_FORWARD); } if (clearOnFailure && !res) { if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { @@ -8063,7 +8062,7 @@ public abstract class Component implements ImageObserver, MenuContainer, toFocus = policy.getDefaultComponent(rootAncestor); } if (toFocus != null) { - res = toFocus.requestFocusInWindow(CausedFocusEvent.Cause.TRAVERSAL_BACKWARD); + res = toFocus.requestFocusInWindow(FocusEvent.Cause.TRAVERSAL_BACKWARD); } } if (clearOnFailure && !res) { @@ -8108,7 +8107,7 @@ public abstract class Component implements ImageObserver, MenuContainer, KeyboardFocusManager.getCurrentKeyboardFocusManager(). setGlobalCurrentFocusCycleRootPriv(fcr); - rootAncestor.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_UP); + rootAncestor.requestFocus(FocusEvent.Cause.TRAVERSAL_UP); } else { Window window = getContainingWindow(); @@ -8118,7 +8117,7 @@ public abstract class Component implements ImageObserver, MenuContainer, if (toFocus != null) { KeyboardFocusManager.getCurrentKeyboardFocusManager(). setGlobalCurrentFocusCycleRootPriv(window); - toFocus.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_UP); + toFocus.requestFocus(FocusEvent.Cause.TRAVERSAL_UP); } } } diff --git a/jdk/src/java.desktop/share/classes/java/awt/Container.java b/jdk/src/java.desktop/share/classes/java/awt/Container.java index a16c2f55d97..04e3f1e89bd 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Container.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Container.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,6 @@ import sun.util.logging.PlatformLogger; import sun.awt.AppContext; import sun.awt.AWTAccessor; -import sun.awt.CausedFocusEvent; import sun.awt.PeerEvent; import sun.awt.SunToolkit; @@ -3515,7 +3514,7 @@ public class Container extends Component { Component toFocus = getFocusTraversalPolicy(). getDefaultComponent(this); if (toFocus != null) { - toFocus.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_DOWN); + toFocus.requestFocus(FocusEvent.Cause.TRAVERSAL_DOWN); } } } diff --git a/jdk/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java b/jdk/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java index b6f1bcfbe4e..ad23e21655a 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java +++ b/jdk/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,6 @@ import sun.util.logging.PlatformLogger; import sun.awt.AppContext; import sun.awt.SunToolkit; import sun.awt.AWTAccessor; -import sun.awt.CausedFocusEvent; import sun.awt.TimedWindowEvent; /** @@ -165,13 +164,13 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { boolean clearOnFailure) { if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.canBeFocusOwner() && - toFocus.requestFocus(false, CausedFocusEvent.Cause.ROLLBACK)) + toFocus.requestFocus(false, FocusEvent.Cause.ROLLBACK)) { return true; } else { Component nextFocus = toFocus.getNextFocusCandidate(); if (nextFocus != null && nextFocus != vetoedComponent && - nextFocus.requestFocusInWindow(CausedFocusEvent.Cause.ROLLBACK)) + nextFocus.requestFocusInWindow(FocusEvent.Cause.ROLLBACK)) { return true; } else if (clearOnFailure) { @@ -431,13 +430,13 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { tempLost, toFocus); } if (tempLost != null) { - tempLost.requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION); + tempLost.requestFocusInWindow(FocusEvent.Cause.ACTIVATION); } if (toFocus != null && toFocus != tempLost) { // If there is a component which requested focus when this window // was inactive it expects to receive focus after activation. - toFocus.requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION); + toFocus.requestFocusInWindow(FocusEvent.Cause.ACTIVATION); } } @@ -490,8 +489,6 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { case FocusEvent.FOCUS_GAINED: { FocusEvent fe = (FocusEvent)e; - CausedFocusEvent.Cause cause = (fe instanceof CausedFocusEvent) ? - ((CausedFocusEvent)fe).getCause() : CausedFocusEvent.Cause.UNKNOWN; Component oldFocusOwner = getGlobalFocusOwner(); Component newFocusOwner = fe.getComponent(); if (oldFocusOwner == newFocusOwner) { @@ -509,10 +506,10 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { if (oldFocusOwner != null) { boolean isEventDispatched = sendMessage(oldFocusOwner, - new CausedFocusEvent(oldFocusOwner, + new FocusEvent(oldFocusOwner, FocusEvent.FOCUS_LOST, fe.isTemporary(), - newFocusOwner, cause)); + newFocusOwner, fe.getCause())); // Failed to dispatch, clear by ourselves if (!isEventDispatched) { setGlobalFocusOwner(null); @@ -552,7 +549,7 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { // Refuse focus on a disabled component if the focus event // isn't of UNKNOWN reason (i.e. not a result of a direct request // but traversal, activation or system generated). - (newFocusOwner.isEnabled() || cause.equals(CausedFocusEvent.Cause.UNKNOWN)))) + (newFocusOwner.isEnabled() || fe.getCause().equals(FocusEvent.Cause.UNKNOWN)))) { // we should not accept focus on such component, so reject it. dequeueKeyEvents(-1, newFocusOwner); @@ -601,10 +598,10 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { Component realOppositeComponent = this.realOppositeComponentWR.get(); if (realOppositeComponent != null && realOppositeComponent != fe.getOppositeComponent()) { - fe = new CausedFocusEvent(newFocusOwner, + fe = new FocusEvent(newFocusOwner, FocusEvent.FOCUS_GAINED, fe.isTemporary(), - realOppositeComponent, cause); + realOppositeComponent, fe.getCause()); ((AWTEvent) fe).isPosted = true; } return typeAheadAssertions(newFocusOwner, fe); @@ -729,10 +726,10 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { oppositeComp = oppositeWindow; } sendMessage(currentFocusOwner, - new CausedFocusEvent(currentFocusOwner, + new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, true, - oppositeComp, CausedFocusEvent.Cause.ACTIVATION)); + oppositeComp, FocusEvent.Cause.ACTIVATION)); } setGlobalFocusedWindow(null); diff --git a/jdk/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java b/jdk/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java index 6b7d779a7db..aa9d64367a4 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java +++ b/jdk/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,6 @@ import sun.util.logging.PlatformLogger; import sun.awt.AppContext; import sun.awt.SunToolkit; -import sun.awt.CausedFocusEvent; import sun.awt.KeyboardFocusManagerPeerProvider; import sun.awt.AWTAccessor; @@ -124,7 +123,7 @@ public abstract class KeyboardFocusManager boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { return KeyboardFocusManager.shouldNativelyFocusHeavyweight( heavyweight, descendant, temporary, focusedWindowChangeAllowed, time, cause); @@ -2164,9 +2163,9 @@ public abstract class KeyboardFocusManager private static final class LightweightFocusRequest { final Component component; final boolean temporary; - final CausedFocusEvent.Cause cause; + final FocusEvent.Cause cause; - LightweightFocusRequest(Component component, boolean temporary, CausedFocusEvent.Cause cause) { + LightweightFocusRequest(Component component, boolean temporary, FocusEvent.Cause cause) { this.component = component; this.temporary = temporary; this.cause = cause; @@ -2190,7 +2189,7 @@ public abstract class KeyboardFocusManager } HeavyweightFocusRequest(Component heavyweight, Component descendant, - boolean temporary, CausedFocusEvent.Cause cause) { + boolean temporary, FocusEvent.Cause cause) { if (log.isLoggable(PlatformLogger.Level.FINE)) { if (heavyweight == null) { log.fine("Assertion (heavyweight != null) failed"); @@ -2202,7 +2201,7 @@ public abstract class KeyboardFocusManager addLightweightRequest(descendant, temporary, cause); } boolean addLightweightRequest(Component descendant, - boolean temporary, CausedFocusEvent.Cause cause) { + boolean temporary, FocusEvent.Cause cause) { if (log.isLoggable(PlatformLogger.Level.FINE)) { if (this == HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { log.fine("Assertion (this != HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) failed"); @@ -2314,7 +2313,7 @@ public abstract class KeyboardFocusManager hwFocusRequest = new HeavyweightFocusRequest(heavyweight, descendant, - temporary, CausedFocusEvent.Cause.UNKNOWN); + temporary, FocusEvent.Cause.UNKNOWN); heavyweightRequests.add(hwFocusRequest); if (currentFocusOwner != null) { @@ -2379,7 +2378,7 @@ public abstract class KeyboardFocusManager */ static int shouldNativelyFocusHeavyweight (Component heavyweight, Component descendant, boolean temporary, - boolean focusedWindowChangeAllowed, long time, CausedFocusEvent.Cause cause) + boolean focusedWindowChangeAllowed, long time, FocusEvent.Cause cause) { if (log.isLoggable(PlatformLogger.Level.FINE)) { if (heavyweight == null) { @@ -2445,7 +2444,7 @@ public abstract class KeyboardFocusManager if (currentFocusOwner != null) { FocusEvent currentFocusOwnerEvent = - new CausedFocusEvent(currentFocusOwner, + new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, temporary, descendant, cause); // Fix 5028014. Rolled out. @@ -2454,7 +2453,7 @@ public abstract class KeyboardFocusManager currentFocusOwnerEvent); } FocusEvent newFocusOwnerEvent = - new CausedFocusEvent(descendant, FocusEvent.FOCUS_GAINED, + new FocusEvent(descendant, FocusEvent.FOCUS_GAINED, temporary, currentFocusOwner, cause); // Fix 5028014. Rolled out. // SunToolkit.postPriorityEvent(newFocusOwnerEvent); @@ -2670,13 +2669,13 @@ public abstract class KeyboardFocusManager * lw requests. */ if (currentFocusOwner != null) { - currentFocusOwnerEvent = new CausedFocusEvent(currentFocusOwner, + currentFocusOwnerEvent = new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, lwFocusRequest.temporary, lwFocusRequest.component, lwFocusRequest.cause); } FocusEvent newFocusOwnerEvent = - new CausedFocusEvent(lwFocusRequest.component, + new FocusEvent(lwFocusRequest.component, FocusEvent.FOCUS_GAINED, lwFocusRequest.temporary, currentFocusOwner == null ? lastFocusOwner : currentFocusOwner, @@ -2726,8 +2725,8 @@ public abstract class KeyboardFocusManager { temporary = true; } - return new CausedFocusEvent(source, fe.getID(), temporary, opposite, - CausedFocusEvent.Cause.NATIVE_SYSTEM); + return new FocusEvent(source, fe.getID(), temporary, opposite, + FocusEvent.Cause.UNEXPECTED); } } @@ -2802,7 +2801,7 @@ public abstract class KeyboardFocusManager // 'opposite' will be fixed by // DefaultKeyboardFocusManager.realOppositeComponent - return new CausedFocusEvent(newSource, + return new FocusEvent(newSource, FocusEvent.FOCUS_GAINED, temporary, opposite, lwFocusRequest.cause); } @@ -2815,8 +2814,8 @@ public abstract class KeyboardFocusManager // If it arrives as the result of activation we should skip it // This event will not have appropriate request record and // on arrival there will be already some focus owner set. - return new CausedFocusEvent(currentFocusOwner, FocusEvent.FOCUS_GAINED, false, - null, CausedFocusEvent.Cause.ACTIVATION); + return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_GAINED, false, + null, FocusEvent.Cause.ACTIVATION); } return retargetUnexpectedFocusEvent(fe); @@ -2839,9 +2838,9 @@ public abstract class KeyboardFocusManager if (currentFocusOwner != null) { // Call to KeyboardFocusManager.clearGlobalFocusOwner() heavyweightRequests.removeFirst(); - return new CausedFocusEvent(currentFocusOwner, + return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, false, null, - CausedFocusEvent.Cause.CLEAR_GLOBAL_FOCUS_OWNER); + FocusEvent.Cause.CLEAR_GLOBAL_FOCUS_OWNER); } // Otherwise, fall through to failure case below @@ -2850,9 +2849,9 @@ public abstract class KeyboardFocusManager { // Focus leaving application if (currentFocusOwner != null) { - return new CausedFocusEvent(currentFocusOwner, + return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, - true, null, CausedFocusEvent.Cause.ACTIVATION); + true, null, FocusEvent.Cause.ACTIVATION); } else { return fe; } @@ -2878,15 +2877,15 @@ public abstract class KeyboardFocusManager ? true : lwFocusRequest.temporary; - return new CausedFocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, + return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, temporary, lwFocusRequest.component, lwFocusRequest.cause); } else if (focusedWindowChanged(opposite, currentFocusOwner)) { // If top-level changed there might be no focus request in a list // But we know the opposite, we now it is temporary - dispatch the event. if (!fe.isTemporary() && currentFocusOwner != null) { // Create copy of the event with only difference in temporary parameter. - fe = new CausedFocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, - true, opposite, CausedFocusEvent.Cause.ACTIVATION); + fe = new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, + true, opposite, FocusEvent.Cause.ACTIVATION); } return fe; } diff --git a/jdk/src/java.desktop/share/classes/java/awt/Window.java b/jdk/src/java.desktop/share/classes/java/awt/Window.java index 5894ad303b7..71fc98009b3 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Window.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Window.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,6 @@ import javax.accessibility.*; import sun.awt.AWTAccessor; import sun.awt.AWTPermissions; import sun.awt.AppContext; -import sun.awt.CausedFocusEvent; import sun.awt.DebugSettings; import sun.awt.SunToolkit; import sun.awt.util.IdentityArrayList; @@ -2599,7 +2598,7 @@ public class Window extends Container implements Accessible { { Component toFocus = KeyboardFocusManager.getMostRecentFocusOwner(owner); - if (toFocus != null && toFocus.requestFocus(false, CausedFocusEvent.Cause.ACTIVATION)) { + if (toFocus != null && toFocus.requestFocus(false, FocusEvent.Cause.ACTIVATION)) { return; } } diff --git a/jdk/src/java.desktop/share/classes/java/awt/event/FocusEvent.java b/jdk/src/java.desktop/share/classes/java/awt/event/FocusEvent.java index afef05edef0..c4483a4d927 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/event/FocusEvent.java +++ b/jdk/src/java.desktop/share/classes/java/awt/event/FocusEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,9 @@ package java.awt.event; import java.awt.Component; +import java.io.ObjectStreamException; + +import sun.awt.AWTAccessor; import sun.awt.AppContext; import sun.awt.SunToolkit; @@ -51,6 +54,10 @@ import sun.awt.SunToolkit; * the FOCUS_GAINED and FOCUS_LOST event ids; the level may be distinguished in * the event using the isTemporary() method. *

    + * Every {@code FocusEvent} records its cause - the reason why this event was + * generated. The cause is assigned during the focus event creation and may be + * retrieved by calling {@link #getCause}. + *

    * An unspecified behavior will be caused if the {@code id} parameter * of any particular {@code FocusEvent} instance is not * in the range from {@code FOCUS_FIRST} to {@code FOCUS_LAST}. @@ -65,6 +72,61 @@ import sun.awt.SunToolkit; */ public class FocusEvent extends ComponentEvent { + /** + * This enum represents the cause of a {@code FocusEvent}- the reason why it + * occurred. Possible reasons include mouse events, keyboard focus + * traversal, window activation. + * If no cause is provided then the reason is {@code UNKNOWN}. + * + * @since 9 + */ + public enum Cause { + /** + * The default value. + */ + UNKNOWN, + /** + * An activating mouse event. + */ + MOUSE_EVENT, + /** + * A focus traversal action with unspecified direction. + */ + TRAVERSAL, + /** + * An up-cycle focus traversal action. + */ + TRAVERSAL_UP, + /** + * A down-cycle focus traversal action. + */ + TRAVERSAL_DOWN, + /** + * A forward focus traversal action. + */ + TRAVERSAL_FORWARD, + /** + * A backward focus traversal action. + */ + TRAVERSAL_BACKWARD, + /** + * Restoring focus after a focus request has been rejected. + */ + ROLLBACK, + /** + * A system action causing an unexpected focus change. + */ + UNEXPECTED, + /** + * An activation of a toplevel window. + */ + ACTIVATION, + /** + * Clearing global focus owner. + */ + CLEAR_GLOBAL_FOCUS_OWNER + } + /** * The first number in the range of ids used for focus events. */ @@ -85,6 +147,16 @@ public class FocusEvent extends ComponentEvent { */ public static final int FOCUS_LOST = 1 + FOCUS_FIRST; //Event.LOST_FOCUS + /** + * A focus event has the reason why this event was generated. + * The cause is set during the focus event creation. + * + * @serial + * @see #getCause() + * @since 9 + */ + private final Cause cause; + /** * A focus event can have two different levels, permanent and temporary. * It will be set to true if some operation takes away the focus @@ -115,7 +187,8 @@ public class FocusEvent extends ComponentEvent { /** * Constructs a {@code FocusEvent} object with the - * specified temporary state and opposite {@code Component}. + * specified temporary state, opposite {@code Component} and the + * {@code Cause.UNKNOWN} cause. * The opposite {@code Component} is the other * {@code Component} involved in this focus change. * For a {@code FOCUS_GAINED} event, this is the @@ -142,13 +215,57 @@ public class FocusEvent extends ComponentEvent { * @see #getID() * @see #isTemporary() * @see #getOppositeComponent() + * @see Cause#UNKNOWN * @since 1.4 */ public FocusEvent(Component source, int id, boolean temporary, Component opposite) { + this(source, id, temporary, opposite, Cause.UNKNOWN); + } + + /** + * Constructs a {@code FocusEvent} object with the + * specified temporary state, opposite {@code Component} and the cause. + * The opposite {@code Component} is the other + * {@code Component} involved in this focus change. + * For a {@code FOCUS_GAINED} event, this is the + * {@code Component} that lost focus. For a + * {@code FOCUS_LOST} event, this is the {@code Component} + * that gained focus. If this focus change occurs with a native + * application, with a Java application in a different VM, + * or with no other {@code Component}, then the opposite + * {@code Component} is {@code null}. + *

    This method throws an + * {@code IllegalArgumentException} if {@code source} or {@code cause} + * is {@code null}. + * + * @param source The {@code Component} that originated the event + * @param id An integer indicating the type of event. + * For information on allowable values, see + * the class description for {@link FocusEvent} + * @param temporary Equals {@code true} if the focus change is temporary; + * {@code false} otherwise + * @param opposite The other Component involved in the focus change, + * or {@code null} + * @param cause The focus event cause. + * @throws IllegalArgumentException if {@code source} equals {@code null} + * or if {@code cause} equals {@code null} + * @see #getSource() + * @see #getID() + * @see #isTemporary() + * @see #getOppositeComponent() + * @see Cause + * @since 9 + */ + public FocusEvent(Component source, int id, boolean temporary, + Component opposite, Cause cause) { super(source, id); + if (cause == null) { + throw new IllegalArgumentException("null cause"); + } this.temporary = temporary; this.opposite = opposite; + this.cause = cause; } /** @@ -220,8 +337,8 @@ public class FocusEvent extends ComponentEvent { return (SunToolkit.targetToAppContext(opposite) == AppContext.getAppContext()) - ? opposite - : null; + ? opposite + : null; } /** @@ -233,17 +350,56 @@ public class FocusEvent extends ComponentEvent { public String paramString() { String typeStr; switch(id) { - case FOCUS_GAINED: - typeStr = "FOCUS_GAINED"; - break; - case FOCUS_LOST: - typeStr = "FOCUS_LOST"; - break; - default: - typeStr = "unknown type"; + case FOCUS_GAINED: + typeStr = "FOCUS_GAINED"; + break; + case FOCUS_LOST: + typeStr = "FOCUS_LOST"; + break; + default: + typeStr = "unknown type"; } return typeStr + (temporary ? ",temporary" : ",permanent") + - ",opposite=" + getOppositeComponent(); + ",opposite=" + getOppositeComponent() + ",cause=" + getCause(); } -} + /** + * Returns the event cause. + * + * @return one of {@link Cause} values + * @since 9 + */ + public final Cause getCause() { + return cause; + } + + /** + * Checks if this deserialized {@code FocusEvent} instance is compatible + * with the current specification which implies that focus event has + * non-null {@code cause} value. If the check fails a new {@code FocusEvent} + * instance is returned which {@code cause} field equals to + * {@link Cause#UNKNOWN} and its other fields have the same values as in + * this {@code FocusEvent} instance. + * + * @serial + * @see #cause + * @since 9 + */ + @SuppressWarnings("serial") + Object readResolve() throws ObjectStreamException { + if (cause != null) { + return this; + } + FocusEvent focusEvent = new FocusEvent(new Component(){}, getID(), + isTemporary(), getOppositeComponent()); + focusEvent.setSource(null); + focusEvent.consumed = consumed; + + AWTAccessor.AWTEventAccessor accessor = + AWTAccessor.getAWTEventAccessor(); + accessor.setBData(focusEvent, accessor.getBData(this)); + return focusEvent; + } + + +} \ No newline at end of file diff --git a/jdk/src/java.desktop/share/classes/java/awt/peer/ComponentPeer.java b/jdk/src/java.desktop/share/classes/java/awt/peer/ComponentPeer.java index 2ac37efb7d1..40890c784e8 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/peer/ComponentPeer.java +++ b/jdk/src/java.desktop/share/classes/java/awt/peer/ComponentPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * 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,12 +27,12 @@ package java.awt.peer; import java.awt.*; import java.awt.event.PaintEvent; +import java.awt.event.FocusEvent.Cause; import java.awt.image.ColorModel; import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; import java.awt.image.VolatileImage; -import sun.awt.CausedFocusEvent; import sun.java2d.pipe.Region; @@ -343,7 +343,7 @@ public interface ComponentPeer { */ boolean requestFocus(Component lightweightChild, boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause); + Cause cause); /** * Returns {@code true} when the component takes part in the focus diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java index 883e0c0cf7c..dd64b77df1d 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3558,7 +3558,7 @@ public abstract class JComponent extends Container implements Serializable, new sun.awt.RequestFocusController() { public boolean acceptRequestFocus(Component from, Component to, boolean temporary, boolean focusedWindowChangeAllowed, - sun.awt.CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { if ((to == null) || !(to instanceof JComponent)) { return true; diff --git a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java index 7d67cd6ae47..796b7ab5d79 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * 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 jdk.internal.misc.Unsafe; import javax.accessibility.AccessibleContext; import java.awt.*; +import java.awt.event.FocusEvent.Cause; import java.awt.dnd.DragSourceContext; import java.awt.dnd.DropTargetContext; import java.awt.dnd.peer.DragSourceContextPeer; @@ -104,7 +105,7 @@ public final class AWTAccessor { /* * Requests focus to the component. */ - boolean requestFocus(Component comp, CausedFocusEvent.Cause cause); + boolean requestFocus(Component comp, Cause cause); /* * Determines if the component can gain focus. */ @@ -438,7 +439,7 @@ public final class AWTAccessor { boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause); + Cause cause); /** * Delivers focus for the lightweight descendant of the heavyweight * synchronously. diff --git a/jdk/src/java.desktop/share/classes/sun/awt/CausedFocusEvent.java b/jdk/src/java.desktop/share/classes/sun/awt/CausedFocusEvent.java index 985b416cffc..638a63f549d 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/CausedFocusEvent.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/CausedFocusEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * 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,17 +27,18 @@ package sun.awt; import java.awt.event.FocusEvent; import java.awt.Component; +import java.io.ObjectStreamException; +import java.lang.reflect.Field; +import java.security.AccessController; +import java.security.PrivilegedAction; /** - * This class represents FocusEvents with a known "cause" - reason why this event happened. It can - * be mouse press, traversal, activation, and so on - all causes are described as Cause enum. The - * event with the cause can be constructed in two ways - explicitly through constructor of - * CausedFocusEvent class or implicitly, by calling appropriate requestFocusXXX method with "cause" - * parameter. The default cause is UNKNOWN. + * This class exists for deserialization compatibility only. */ -@SuppressWarnings("serial") -public class CausedFocusEvent extends FocusEvent { - public enum Cause { +class CausedFocusEvent extends FocusEvent { + private static final long serialVersionUID = -3647309088427840738L; + + private enum Cause { UNKNOWN, MOUSE_EVENT, TRAVERSAL, @@ -51,39 +52,82 @@ public class CausedFocusEvent extends FocusEvent { NATIVE_SYSTEM, ACTIVATION, CLEAR_GLOBAL_FOCUS_OWNER, - RETARGETED + RETARGETED; }; + @SuppressWarnings("serial") + private static final Component dummy = new Component(){}; + private final Cause cause; - public Cause getCause() { - return cause; - } - - public String toString() { - return "java.awt.FocusEvent[" + super.paramString() + ",cause=" + cause + "] on " + getSource(); - } - - public CausedFocusEvent(Component source, int id, boolean temporary, + private CausedFocusEvent(Component source, int id, boolean temporary, Component opposite, Cause cause) { super(source, id, temporary, opposite); - if (cause == null) { - cause = Cause.UNKNOWN; - } - this.cause = cause; + throw new IllegalStateException(); } - /** - * Retargets the original focus event to the new target. If the - * original focus event is CausedFocusEvent, it remains such and - * cause is copied. Otherwise, new CausedFocusEvent is created, - * with cause as RETARGETED. - * @return retargeted event, or null if e is null - */ - public static FocusEvent retarget(FocusEvent e, Component newSource) { - if (e == null) return null; + Object readResolve() throws ObjectStreamException { + FocusEvent.Cause newCause; + switch (cause) { + case UNKNOWN: + newCause = FocusEvent.Cause.UNKNOWN; + break; + case MOUSE_EVENT: + newCause = FocusEvent.Cause.MOUSE_EVENT; + break; + case TRAVERSAL: + newCause = FocusEvent.Cause.TRAVERSAL; + break; + case TRAVERSAL_UP: + newCause = FocusEvent.Cause.TRAVERSAL_UP; + break; + case TRAVERSAL_DOWN: + newCause = FocusEvent.Cause.TRAVERSAL_DOWN; + break; + case TRAVERSAL_FORWARD: + newCause = FocusEvent.Cause.TRAVERSAL_FORWARD; + break; + case TRAVERSAL_BACKWARD: + newCause = FocusEvent.Cause.TRAVERSAL_BACKWARD; + break; + case ROLLBACK: + newCause = FocusEvent.Cause.ROLLBACK; + break; + case NATIVE_SYSTEM: + newCause = FocusEvent.Cause.UNEXPECTED; + break; + case ACTIVATION: + newCause = FocusEvent.Cause.ACTIVATION; + break; + case CLEAR_GLOBAL_FOCUS_OWNER: + newCause = FocusEvent.Cause.CLEAR_GLOBAL_FOCUS_OWNER; + break; + default: + newCause = FocusEvent.Cause.UNKNOWN; + } - return new CausedFocusEvent(newSource, e.getID(), e.isTemporary(), e.getOppositeComponent(), - (e instanceof CausedFocusEvent) ? ((CausedFocusEvent)e).getCause() : Cause.RETARGETED); + FocusEvent focusEvent = new FocusEvent(dummy, getID(), isTemporary(), + getOppositeComponent(), newCause); + focusEvent.setSource(null); + try { + final Field consumedField = FocusEvent.class.getField("consumed"); + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Object run() { + consumedField.setAccessible(true); + try { + consumedField.set(focusEvent, consumed); + } catch (IllegalAccessException e) { + } + return null; + } + }); + } catch (NoSuchFieldException e) { + } + + AWTAccessor.AWTEventAccessor accessor = + AWTAccessor.getAWTEventAccessor(); + accessor.setBData(focusEvent, accessor.getBData(this)); + return focusEvent; } } diff --git a/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java b/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java index 11b54c807c4..b82f1833177 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,8 +60,8 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag focusLog.fine("Clearing global focus owner " + focusOwner); } if (focusOwner != null) { - FocusEvent fl = new CausedFocusEvent(focusOwner, FocusEvent.FOCUS_LOST, false, null, - CausedFocusEvent.Cause.CLEAR_GLOBAL_FOCUS_OWNER); + FocusEvent fl = new FocusEvent(focusOwner, FocusEvent.FOCUS_LOST, false, null, + FocusEvent.Cause.CLEAR_GLOBAL_FOCUS_OWNER); SunToolkit.postPriorityEvent(fl); } } @@ -110,7 +110,7 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause, + FocusEvent.Cause cause, Component currentFocusOwner) // provided by the descendant peers { if (lightweightChild == null) { @@ -122,7 +122,7 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag currentOwner = null; } if (currentOwner != null) { - FocusEvent fl = new CausedFocusEvent(currentOwner, FocusEvent.FOCUS_LOST, + FocusEvent fl = new FocusEvent(currentOwner, FocusEvent.FOCUS_LOST, false, lightweightChild, cause); if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { @@ -131,7 +131,7 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag SunToolkit.postEvent(SunToolkit.targetToAppContext(currentOwner), fl); } - FocusEvent fg = new CausedFocusEvent(lightweightChild, FocusEvent.FOCUS_GAINED, + FocusEvent fg = new FocusEvent(lightweightChild, FocusEvent.FOCUS_GAINED, false, currentOwner, cause); if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { @@ -142,7 +142,7 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag } // WARNING: Don't call it on the Toolkit thread. - public static boolean requestFocusFor(Component target, CausedFocusEvent.Cause cause) { + public static boolean requestFocusFor(Component target, FocusEvent.Cause cause) { return AWTAccessor.getComponentAccessor().requestFocus(target, cause); } @@ -152,7 +152,7 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { return KfmAccessor.instance.shouldNativelyFocusHeavyweight( heavyweight, descendant, temporary, focusedWindowChangeAllowed, diff --git a/jdk/src/java.desktop/share/classes/sun/awt/NullComponentPeer.java b/jdk/src/java.desktop/share/classes/sun/awt/NullComponentPeer.java index d44e8ca2535..f95df58145f 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/NullComponentPeer.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/NullComponentPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Insets; -import java.awt.MenuBar; +import java.awt.event.FocusEvent.Cause; import java.awt.Point; import java.awt.Event; import java.awt.event.PaintEvent; @@ -178,7 +178,7 @@ public class NullComponentPeer implements LightweightPeer, public boolean requestFocus (Component lightweightChild, boolean temporary, - boolean focusedWindowChangeAllowed, long time, CausedFocusEvent.Cause cause) { + boolean focusedWindowChangeAllowed, long time, Cause cause) { return false; } diff --git a/jdk/src/java.desktop/share/classes/sun/awt/RequestFocusController.java b/jdk/src/java.desktop/share/classes/sun/awt/RequestFocusController.java index a0b9a3ee12b..29c94c6ab1b 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/RequestFocusController.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/RequestFocusController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,11 @@ package sun.awt; import java.awt.Component; +import java.awt.event.FocusEvent.Cause; public interface RequestFocusController { public boolean acceptRequestFocus(Component from, Component to, boolean temporary, boolean focusedWindowChangeAllowed, - CausedFocusEvent.Cause cause); + Cause cause); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java index 82715e73ff2..c65a7c79f96 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -287,7 +287,7 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget @SuppressWarnings("deprecation") public final boolean requestFocus(Component lightweightChild, boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { if (XKeyboardFocusManagerPeer. processSynchronousLightweightTransfer(target, lightweightChild, temporary, @@ -527,7 +527,7 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget // WindowEvent wfg = new WindowEvent(parentWindow, WindowEvent.WINDOW_GAINED_FOCUS); // parentWindow.dispatchEvent(wfg); // } - XKeyboardFocusManagerPeer.requestFocusFor(target, CausedFocusEvent.Cause.MOUSE_EVENT); + XKeyboardFocusManagerPeer.requestFocusFor(target, FocusEvent.Cause.MOUSE_EVENT); } break; } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedCanvasPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedCanvasPeer.java index 9370b8cdae4..e81ff91575c 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedCanvasPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedCanvasPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -430,13 +430,10 @@ public class XEmbedCanvasPeer extends XCanvasPeer implements WindowFocusListener if (isXEmbedActive()) { xembedLog.fine("Forwarding FOCUS_GAINED"); int flavor = XEMBED_FOCUS_CURRENT; - if (e instanceof CausedFocusEvent) { - CausedFocusEvent ce = (CausedFocusEvent)e; - if (ce.getCause() == CausedFocusEvent.Cause.TRAVERSAL_FORWARD) { - flavor = XEMBED_FOCUS_FIRST; - } else if (ce.getCause() == CausedFocusEvent.Cause.TRAVERSAL_BACKWARD) { - flavor = XEMBED_FOCUS_LAST; - } + if (e.getCause() == FocusEvent.Cause.TRAVERSAL_FORWARD) { + flavor = XEMBED_FOCUS_FIRST; + } else if (e.getCause() == FocusEvent.Cause.TRAVERSAL_BACKWARD) { + flavor = XEMBED_FOCUS_LAST; } xembed.sendMessage(xembed.handle, XEMBED_FOCUS_IN, flavor, 0, 0); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedChildProxyPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedChildProxyPeer.java index 6bb38b54f24..d8fe392fe2c 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedChildProxyPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedChildProxyPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -195,7 +195,7 @@ public class XEmbedChildProxyPeer implements ComponentPeer, XEventDispatcher{ boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { int result = XKeyboardFocusManagerPeer .shouldNativelyFocusHeavyweight(proxy, lightweightChild, diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XKeyboardFocusManagerPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XKeyboardFocusManagerPeer.java index dde0b87d64c..2ec736feb29 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XKeyboardFocusManagerPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XKeyboardFocusManagerPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ import java.awt.Component; import java.awt.Window; import sun.awt.AWTAccessor; -import sun.awt.CausedFocusEvent; +import java.awt.event.FocusEvent; import sun.awt.KeyboardFocusManagerPeerImpl; import sun.util.logging.PlatformLogger; @@ -101,7 +101,7 @@ public class XKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl { boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { return KeyboardFocusManagerPeerImpl.deliverFocus(lightweightChild, target, diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextAreaPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextAreaPeer.java index 9efe70b17c4..5d769203159 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextAreaPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextAreaPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * 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,7 +59,6 @@ import javax.swing.text.JTextComponent; import javax.swing.plaf.BorderUIResource; import java.awt.im.InputMethodRequests; -import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; import sun.awt.SunToolkit; @@ -945,14 +944,16 @@ final class XTextAreaPeer extends XComponentPeer implements TextAreaPeer { void forwardFocusGained( FocusEvent e) { isFocused = true; - FocusEvent fe = CausedFocusEvent.retarget(e, this); + FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), + e.getOppositeComponent(), e.getCause()); super.processFocusEvent(fe); } void forwardFocusLost( FocusEvent e) { isFocused = false; - FocusEvent fe = CausedFocusEvent.retarget(e, this); + FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), + e.getOppositeComponent(), e.getCause()); super.processFocusEvent(fe); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextFieldPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextFieldPeer.java index 9df078e9d1f..42730dce98f 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextFieldPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextFieldPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,6 @@ import java.awt.im.InputMethodRequests; import sun.util.logging.PlatformLogger; -import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { @@ -618,13 +617,15 @@ final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { void forwardFocusGained( FocusEvent e) { isFocused = true; - FocusEvent fe = CausedFocusEvent.retarget(e, this); + FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), + e.getOppositeComponent(), e.getCause()); super.processFocusEvent(fe); } void forwardFocusLost( FocusEvent e) { isFocused = false; - FocusEvent fe = CausedFocusEvent.retarget(e, this); + FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), + e.getOppositeComponent(), e.getCause()); super.processFocusEvent(fe); } diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java index 51e16b0a1f1..f07857b80b4 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import java.awt.*; import java.awt.peer.*; import java.awt.image.VolatileImage; import sun.awt.RepaintArea; -import sun.awt.CausedFocusEvent; import sun.awt.image.SunVolatileImage; import sun.awt.image.ToolkitImage; import java.awt.image.BufferedImage; @@ -321,7 +320,7 @@ public abstract class WComponentPeer extends WObjectPeer WKeyboardFocusManagerPeer.shouldFocusOnClick((Component)target)) { WKeyboardFocusManagerPeer.requestFocusFor((Component)target, - CausedFocusEvent.Cause.MOUSE_EVENT); + FocusEvent.Cause.MOUSE_EVENT); } break; } @@ -687,7 +686,7 @@ public abstract class WComponentPeer extends WObjectPeer @Override public boolean requestFocus(Component lightweightChild, boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause) + FocusEvent.Cause cause) { if (WKeyboardFocusManagerPeer. processSynchronousLightweightTransfer((Component)target, lightweightChild, temporary, diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java index 383254b815a..40c995def1d 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package sun.awt.windows; import java.awt.*; +import java.awt.event.FocusEvent.Cause; import java.awt.dnd.DropTarget; import java.awt.peer.*; import java.io.File; @@ -34,7 +35,6 @@ import java.security.PrivilegedAction; import java.util.ResourceBundle; import java.util.MissingResourceException; import java.util.Vector; -import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer { @@ -282,7 +282,7 @@ final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer { @Override public boolean requestFocus (Component lightweightChild, boolean temporary, - boolean focusedWindowChangeAllowed, long time, CausedFocusEvent.Cause cause) + boolean focusedWindowChangeAllowed, long time, Cause cause) { return false; } diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WKeyboardFocusManagerPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WKeyboardFocusManagerPeer.java index a475328881a..f11409d4aca 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WKeyboardFocusManagerPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WKeyboardFocusManagerPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import java.awt.peer.ComponentPeer; import sun.awt.AWTAccessor; import sun.awt.AWTAccessor.ComponentAccessor; import sun.awt.KeyboardFocusManagerPeerImpl; -import sun.awt.CausedFocusEvent; +import java.awt.event.FocusEvent.Cause; final class WKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl { static native void setNativeFocusOwner(ComponentPeer peer); @@ -75,7 +75,7 @@ final class WKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl { boolean temporary, boolean focusedWindowChangeAllowed, long time, - CausedFocusEvent.Cause cause) + Cause cause) { // TODO: do something to eliminate this forwarding return KeyboardFocusManagerPeerImpl.deliverFocus(lightweightChild, diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java index a80e7dd6d13..d4ae0eb491e 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * 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,11 +26,11 @@ package sun.awt.windows; import java.awt.*; +import java.awt.event.FocusEvent.Cause; import java.awt.peer.DialogPeer; import java.awt.peer.ComponentPeer; import java.awt.dnd.DropTarget; import java.util.Vector; -import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; class WPrintDialogPeer extends WWindowPeer implements DialogPeer { @@ -153,7 +153,7 @@ class WPrintDialogPeer extends WWindowPeer implements DialogPeer { @Override public boolean requestFocus (Component lightweightChild, boolean temporary, - boolean focusedWindowChangeAllowed, long time, CausedFocusEvent.Cause cause) + boolean focusedWindowChangeAllowed, long time, Cause cause) { return false; diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java index 12885ad2a61..2e8e81262d4 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -300,11 +300,11 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, return getNativeWindowSize(); } - public boolean requestWindowFocus(CausedFocusEvent.Cause cause) { + public boolean requestWindowFocus(FocusEvent.Cause cause) { if (!focusAllowedFor()) { return false; } - return requestWindowFocus(cause == CausedFocusEvent.Cause.MOUSE_EVENT); + return requestWindowFocus(cause == FocusEvent.Cause.MOUSE_EVENT); } private native boolean requestWindowFocus(boolean isMouseEventCause); diff --git a/jdk/test/java/awt/Focus/Cause/FocusCauseTest.java b/jdk/test/java/awt/Focus/Cause/FocusCauseTest.java new file mode 100644 index 00000000000..129c3b6dd24 --- /dev/null +++ b/jdk/test/java/awt/Focus/Cause/FocusCauseTest.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8080395 + @summary consider making sun.awt.CausedFocusEvent functionality public + @run main FocusCauseTest +*/ + + +import java.awt.*; +import java.awt.event.FocusEvent.Cause; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.lang.IllegalArgumentException; +import java.lang.Override; +import java.lang.RuntimeException; +import java.util.Arrays; + +public class FocusCauseTest { + + private static Cause[] causes1 = {Cause.ACTIVATION, + Cause.UNKNOWN, Cause.UNKNOWN, Cause.TRAVERSAL_FORWARD, + Cause.TRAVERSAL_FORWARD, Cause.TRAVERSAL_BACKWARD, + Cause.TRAVERSAL_BACKWARD, Cause.TRAVERSAL_UP, + Cause.TRAVERSAL_DOWN, Cause.CLEAR_GLOBAL_FOCUS_OWNER}; + private static Cause[] causes2 = new Cause[10]; + private static int cnt; + + static byte[] data = + {-84, -19, 0, 5, 115, 114, 0, 24, 115, 117, 110, 46, 97, 119, + 116, 46, 67, 97, 117, 115, 101, 100, 70, 111, 99, 117, 115, 69, 118, + 101, 110, 116, -51, 98, 39, -75, 86, 52, 107, 30, 2, 0, 1, 76, 0, 5, + 99, 97, 117, 115, 101, 116, 0, 32, 76, 115, 117, 110, 47, 97, 119, + 116, 47, 67, 97, 117, 115, 101, 100, 70, 111, 99, 117, 115, 69, 118, + 101, 110, 116, 36, 67, 97, 117, 115, 101, 59, 120, 114, 0, 25, 106, + 97, 118, 97, 46, 97, 119, 116, 46, 101, 118, 101, 110, 116, 46, 70, + 111, 99, 117, 115, 69, 118, 101, 110, 116, 7, 68, -65, 75, 55, -113, + 98, -52, 2, 0, 1, 90, 0, 9, 116, 101, 109, 112, 111, 114, 97, 114, + 121, 120, 114, 0, 29, 106, 97, 118, 97, 46, 97, 119, 116, 46, 101, + 118, 101, 110, 116, 46, 67, 111, 109, 112, 111, 110, 101, 110, 116, + 69, 118, 101, 110, 116, 112, 109, -6, -107, 79, -87, -38, 69, 2, 0, + 0, 120, 114, 0, 17, 106, 97, 118, 97, 46, 97, 119, 116, 46, 65, 87, + 84, 69, 118, 101, 110, 116, -26, -85, 45, -31, 24, -33, -118, -61, + 2, 0, 3, 90, 0, 8, 99, 111, 110, 115, 117, 109, 101, 100, 73, 0, 2, + 105, 100, 91, 0, 5, 98, 100, 97, 116, 97, 116, 0, 2, 91, 66, 120, + 114, 0, 21, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 69, 118, + 101, 110, 116, 79, 98, 106, 101, 99, 116, 76, -115, 9, 78, 24, 109, + 125, -88, 2, 0, 0, 120, 112, 0, 0, 0, 3, -20, 112, 0, 126, 114, 0, + 30, 115, 117, 110, 46, 97, 119, 116, 46, 67, 97, 117, 115, 101, 100, + 70, 111, 99, 117, 115, 69, 118, 101, 110, 116, 36, 67, 97, 117, 115, + 101, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 120, 114, 0, 14, 106, 97, + 118, 97, 46, 108, 97, 110, 103, 46, 69, 110, 117, 109, 0, 0, 0, 0, + 0, 0, 0, 0, 18, 0, 0, 120, 112, 116, 0}; + + static byte[] dataOld = + {-84, -19, 0, 5, 115, 114, 0, 25, 106, 97, 118, 97, 46, 97, 119, + 116, 46, 101, 118, 101, 110, 116, 46, 70, 111, 99, 117, 115, 69, + 118, 101, 110, 116, 7, 68, -65, 75, 55, -113, 98, -52, 2, 0, 1, 90, + 0, 9, 116, 101, 109, 112, 111, 114, 97, 114, 121, 120, 114, 0, 29, + 106, 97, 118, 97, 46, 97, 119, 116, 46, 101, 118, 101, 110, 116, 46, + 67, 111, 109, 112, 111, 110, 101, 110, 116, 69, 118, 101, 110, 116, + 112, 109, -6, -107, 79, -87, -38, 69, 2, 0, 0, 120, 114, 0, 17, 106, + 97, 118, 97, 46, 97, 119, 116, 46, 65, 87, 84, 69, 118, 101, 110, + 116, -26, -85, 45, -31, 24, -33, -118, -61, 2, 0, 3, 90, 0, 8, 99, + 111, 110, 115, 117, 109, 101, 100, 73, 0, 2, 105, 100, 91, 0, 5, 98, + 100, 97, 116, 97, 116, 0, 2, 91, 66, 120, 114, 0, 21, 106, 97, 118, + 97, 46, 117, 116, 105, 108, 46, 69, 118, 101, 110, 116, 79, 98, 106, + 101, 99, 116, 76, -115, 9, 78, 24, 109, 125, -88, 2, 0, 0, 120, 112, + 0, 0, 0, 0, 100, 112, 0}; + + static String[] causesIn = {"UNKNOWN", "MOUSE_EVENT", "TRAVERSAL", + "TRAVERSAL_UP", "TRAVERSAL_DOWN", "TRAVERSAL_FORWARD", + "TRAVERSAL_BACKWARD", "MANUAL_REQUEST", "AUTOMATIC_TRAVERSE" + ,"ROLLBACK", "NATIVE_SYSTEM", "ACTIVATION", + "CLEAR_GLOBAL_FOCUS_OWNER", "RETARGETED"}; + + static FocusEvent.Cause[] causesOut = {FocusEvent.Cause.UNKNOWN, + FocusEvent.Cause.MOUSE_EVENT, + FocusEvent.Cause.TRAVERSAL, FocusEvent.Cause.TRAVERSAL_UP, + FocusEvent.Cause.TRAVERSAL_DOWN, FocusEvent.Cause.TRAVERSAL_FORWARD, + FocusEvent.Cause.TRAVERSAL_BACKWARD, FocusEvent.Cause.UNKNOWN, + FocusEvent.Cause.UNKNOWN, FocusEvent.Cause.ROLLBACK, + FocusEvent.Cause.UNEXPECTED, FocusEvent.Cause.ACTIVATION, + FocusEvent.Cause.CLEAR_GLOBAL_FOCUS_OWNER, FocusEvent.Cause.UNKNOWN + }; + + public static void main(String[] args) throws Exception { + testCauses(); + testNullCause(); + testCausedFocusEventDeserialization(); + testFocusEventDeserialization(); + System.out.println("ok"); + } + + private static void testNullCause() { + try { + new FocusEvent(new Frame(), FocusEvent.FOCUS_GAINED, true, + null, null); + throw new RuntimeException("Exception is not thrown when the " + + "cause is null"); + } catch (IllegalArgumentException e) { + } + } + + private static void testCauses() throws Exception { + cnt = 0; + Frame frame = new Frame(); + TextField comp1 = new TextField(); + comp1.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + System.out.println(e.getCause()); + causes2[cnt++] = e.getCause(); + } + + @Override + public void focusLost(FocusEvent e) { + System.out.println(e.getCause()); + causes2[cnt++] = e.getCause(); + } + }); + TextField comp2 = new TextField(); + comp2.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + System.out.println(e.getCause()); + causes2[cnt++] = e.getCause(); + } + + @Override + public void focusLost(FocusEvent e) { + System.out.println(e.getCause()); + causes2[cnt++] = e.getCause(); + } + }); + frame.add(comp1, BorderLayout.NORTH); + frame.add(comp2, BorderLayout.SOUTH); + frame.setVisible(true); + + Robot robot = new Robot(); + robot.delay(200); + robot.waitForIdle(); + comp2.requestFocus(); + robot.waitForIdle(); + comp2.transferFocus(); + robot.waitForIdle(); + comp1.transferFocusBackward(); + robot.waitForIdle(); + comp2.transferFocusUpCycle(); + robot.waitForIdle(); + frame.transferFocusDownCycle(); + robot.waitForIdle(); + frame.dispose(); + robot.waitForIdle(); + if (!Arrays.equals(causes1, causes2)) { + throw new RuntimeException("wrong cause " + causes2); + } + } + + private static void testCausedFocusEventDeserialization() throws + Exception { + for (int i = 0; i < causesIn.length; i++) { + final String causeIn = causesIn[i]; + ObjectInputStream oi = new ObjectInputStream(new InputStream() { + int cnt = 0; + @Override + public int read() throws IOException { + if(cnt < data.length) { + return data[cnt++]; + } else if(cnt == data.length){ + cnt++; + return causeIn.length(); + } else if(cnt - data.length - 1 < causeIn.length()) { + return causeIn.getBytes()[cnt++ - data.length - 1]; + } + return -1; + } + }); + FocusEvent ev = (FocusEvent) oi.readObject(); + System.out.println(ev); + if(ev.getCause() != causesOut[i]) { + throw new RuntimeException("Wrong cause read :" +ev.getCause()); + } + } + } + + private static void testFocusEventDeserialization() throws + Exception { + ObjectInputStream oi = new ObjectInputStream( + new ByteArrayInputStream(dataOld)); + FocusEvent ev = (FocusEvent)oi.readObject(); + if(ev.getCause() != FocusEvent.Cause.UNKNOWN) { + throw new RuntimeException("Wrong cause in deserialized FocusEvent " + + ev.getCause()); + } + } + +} From dc0aed8917af20d28df38590998d116ab6b6070d Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Fri, 15 Apr 2016 09:54:27 +0300 Subject: [PATCH 083/222] 8153276: [TEST_BUG] javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java Reviewed-by: alexsch, yan --- .../ShellFolderQueries/ShellFolderQueriesTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java b/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java index 0892b5e2090..3cd85f21823 100644 --- a/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java +++ b/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java @@ -30,7 +30,6 @@ * @run main ShellFolderQueriesTest */ -import sun.awt.OSInfo; import javax.swing.filechooser.FileSystemView; import java.io.File; @@ -50,7 +49,8 @@ public class ShellFolderQueriesTest { static String scriptEnd = "\"\noShellLink.WindowStyle = 1\noShellLink.Save"; public static void main(String[] args) throws Exception { - if(OSInfo.getOSType() == OSInfo.OSType.WINDOWS) { + if(System.getProperty("os.name").toLowerCase().contains("windows")) { + System.out.println("Windows detected: will run shortcut test"); testGet(); testLink(); } else { From 3029b6b065f7d455225cb65ca23f33a74858da4e Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Fri, 15 Apr 2016 09:59:36 +0300 Subject: [PATCH 084/222] 8145787: [TEST_BUG][PIT] javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java fails with CannotUndoException Reviewed-by: alexsch, serb --- .../AbstractDocumentUndoConcurrentTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java b/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java index 30c48df47f8..a425f5a0fe0 100644 --- a/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java +++ b/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,8 +104,12 @@ public class AbstractDocumentUndoConcurrentTest { e.printStackTrace(); } for (int i = 0; i < 1000; i++) { - undoManager.undoOrRedo(); - undoManager.undo(); + if(undoManager.canUndoOrRedo()) { + undoManager.undoOrRedo(); + } + if(undoManager.canUndo()) { + undoManager.undo(); + } } System.out.println("t3 done"); } From d20efa360f420a46c3057c15ea7cfd392cbedaa5 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 15 Apr 2016 11:39:31 +0200 Subject: [PATCH 085/222] 8154283: Check for clash between package and class not working when package in a different module Looking for any visible package when checking for package-class clash Reviewed-by: jjg --- .../com/sun/tools/javac/code/Symtab.java | 2 +- .../com/sun/tools/javac/comp/MemberEnter.java | 4 -- .../test/tools/javac/modules/EdgeCases.java | 37 ++++++++++++++++++- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index db9d1bbfda6..2d1c87d3272 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -698,7 +698,7 @@ public class Symtab { */ public boolean packageExists(ModuleSymbol msym, Name fullname) { Assert.checkNonNull(msym); - return enterPackage(msym, fullname).exists(); + return lookupPackage(msym, fullname).exists(); } /** Make a package, given its fully qualified name. diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java index 48ebd8e74ca..8db5f0899e0 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -53,10 +53,6 @@ import static com.sun.tools.javac.code.TypeTag.TYPEVAR; public class MemberEnter extends JCTree.Visitor { protected static final Context.Key memberEnterKey = new Context.Key<>(); - /** A switch to determine whether we check for package/class conflicts - */ - final static boolean checkClash = true; - private final Enter enter; private final Log log; private final Check chk; diff --git a/langtools/test/tools/javac/modules/EdgeCases.java b/langtools/test/tools/javac/modules/EdgeCases.java index c85f364f3c8..4c80bd4f7b4 100644 --- a/langtools/test/tools/javac/modules/EdgeCases.java +++ b/langtools/test/tools/javac/modules/EdgeCases.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8154283 * @summary tests for multi-module mode compilation * @library /tools/lib * @modules @@ -57,7 +58,6 @@ import com.sun.tools.javac.code.Symbol.ModuleSymbol; import toolbox.JarTask; import toolbox.JavacTask; import toolbox.Task; -import toolbox.ToolBox; public class EdgeCases extends ModuleTestBase { @@ -269,4 +269,39 @@ public class EdgeCases extends ModuleTestBase { } + @Test + void testClassPackageClash(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports test.m1; }", + "package test.m1;\n" + + "public class Test {}\n"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { requires m1; }", + "package test;\n" + + "public class m1 {}\n"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log = new JavacTask(tb) + .options("-modulesourcepath", src.toString(), + "-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = Arrays.asList( + "m1.java:2:8: compiler.err.clash.with.pkg.of.same.name: kindname.class, test.m1", + "1 error" + ); + + if (!expected.equals(log)) { + throw new IllegalStateException(log.toString()); + } + } + } From 65bd7fafd82cf9cc64dd028edb55cb93df2f9a6d Mon Sep 17 00:00:00 2001 From: Ajit Ghaisas Date: Fri, 15 Apr 2016 15:50:45 +0530 Subject: [PATCH 086/222] 8049069: JButton incorrect behaviour on button release Reviewed-by: serb, alexsch --- .../classes/javax/swing/SwingUtilities.java | 44 ++++++- .../JButton/PressedButtonRightClickTest.java | 112 ++++++++++++++++++ 2 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 jdk/test/javax/swing/JButton/PressedButtonRightClickTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/SwingUtilities.java b/jdk/src/java.desktop/share/classes/javax/swing/SwingUtilities.java index 6a48eb423a3..9900c9b7e0e 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/SwingUtilities.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/SwingUtilities.java @@ -845,6 +845,38 @@ public class SwingUtilities implements SwingConstants return result; } + /** + * Check whether MouseEvent contains speficied mouse button or + * mouse button down mask based on MouseEvent ID. + * + * @param anEvent a MouseEvent object + * @param mouseButton mouse button type + * @param mouseButtonDownMask mouse button down mask event modifier + * + * @return true if the anEvent contains speficied mouseButton or + * mouseButtonDownMask based on MouseEvent ID. + */ + private static boolean checkMouseButton(MouseEvent anEvent, + int mouseButton, + int mouseButtonDownMask) + { + switch (anEvent.getID()) { + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + case MouseEvent.MOUSE_CLICKED: + return (anEvent.getButton() == mouseButton); + + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + case MouseEvent.MOUSE_DRAGGED: + return ((anEvent.getModifiersEx() & mouseButtonDownMask) != 0); + + default: + return ((anEvent.getModifiersEx() & mouseButtonDownMask) != 0 || + anEvent.getButton() == mouseButton); + } + } + /** * Returns true if the mouse event specifies the left mouse button. * @@ -852,8 +884,8 @@ public class SwingUtilities implements SwingConstants * @return true if the left mouse button was active */ public static boolean isLeftMouseButton(MouseEvent anEvent) { - return ((anEvent.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0 || - anEvent.getButton() == MouseEvent.BUTTON1); + return checkMouseButton(anEvent, MouseEvent.BUTTON1, + InputEvent.BUTTON1_DOWN_MASK); } /** @@ -863,8 +895,8 @@ public class SwingUtilities implements SwingConstants * @return true if the middle mouse button was active */ public static boolean isMiddleMouseButton(MouseEvent anEvent) { - return ((anEvent.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0 || - anEvent.getButton() == MouseEvent.BUTTON2); + return checkMouseButton(anEvent, MouseEvent.BUTTON2, + InputEvent.BUTTON2_DOWN_MASK); } /** @@ -874,8 +906,8 @@ public class SwingUtilities implements SwingConstants * @return true if the right mouse button was active */ public static boolean isRightMouseButton(MouseEvent anEvent) { - return ((anEvent.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 || - anEvent.getButton() == MouseEvent.BUTTON3); + return checkMouseButton(anEvent, MouseEvent.BUTTON3, + InputEvent.BUTTON3_DOWN_MASK); } /** diff --git a/jdk/test/javax/swing/JButton/PressedButtonRightClickTest.java b/jdk/test/javax/swing/JButton/PressedButtonRightClickTest.java new file mode 100644 index 00000000000..c4cddc71f18 --- /dev/null +++ b/jdk/test/javax/swing/JButton/PressedButtonRightClickTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 8049069 + * @summary Tests whether right mouse click releases a pressed JButton + */ + +public class PressedButtonRightClickTest { + + private static Robot testRobot; + private static JFrame myFrame; + private static JButton myButton; + + public static void main(String[] args) throws Throwable { + + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + constructTestUI(); + } + }); + + try { + testRobot = new Robot(); + } catch (AWTException ex) { + throw new RuntimeException("Exception in Robot creation"); + } + + testRobot.waitForIdle(); + + // Method performing auto test operation + test(); + + disposeTestUI(); + } + + private static void test() { + Point loc = myFrame.getLocationOnScreen(); + + testRobot.mouseMove((loc.x + 100), (loc.y + 100)); + + // Press the left mouse button + testRobot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + myButton.setText("Left button pressed"); + testRobot.delay(1000); + + // Press the right mouse button + testRobot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + myButton.setText("Left button pressed + Right button pressed"); + testRobot.delay(1000); + + // Release the right mouse button + testRobot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + myButton.setText("Right button released"); + testRobot.delay(1000); + + // Test whether the button is still pressed + if (myButton.getModel().isPressed() == false) { + disposeTestUI(); + throw new RuntimeException("Test Failed!"); + } + } + + private static void disposeTestUI() { + myFrame.setVisible(false); + myFrame.dispose(); + } + + public static void constructTestUI() { + myFrame = new JFrame(); + myFrame.setLayout(new BorderLayout()); + myButton = new JButton("Whatever"); + myFrame.add(myButton, BorderLayout.CENTER); + myFrame.setSize(400, 300); + myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + myFrame.setVisible(true); + } +} + From b4712438319af7ae4fa5dbd49720782bec51b595 Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Fri, 15 Apr 2016 19:15:12 +0400 Subject: [PATCH 087/222] 8132791: No access to SynthContext.getContext() Reviewed-by: serb, ssadetsky --- .../swing/plaf/synth/SynthArrowButton.java | 1 - .../javax/swing/plaf/synth/SynthBorder.java | 1 - .../javax/swing/plaf/synth/SynthButtonUI.java | 9 ---- .../swing/plaf/synth/SynthColorChooserUI.java | 5 --- .../swing/plaf/synth/SynthComboBoxUI.java | 4 -- .../javax/swing/plaf/synth/SynthContext.java | 42 +++++-------------- .../swing/plaf/synth/SynthDefaultLookup.java | 1 - .../swing/plaf/synth/SynthDesktopIconUI.java | 4 -- .../swing/plaf/synth/SynthDesktopPaneUI.java | 4 -- .../swing/plaf/synth/SynthEditorPaneUI.java | 3 -- .../synth/SynthInternalFrameTitlePane.java | 6 --- .../plaf/synth/SynthInternalFrameUI.java | 4 -- .../javax/swing/plaf/synth/SynthLabelUI.java | 8 ---- .../javax/swing/plaf/synth/SynthListUI.java | 3 -- .../swing/plaf/synth/SynthLookAndFeel.java | 1 - .../swing/plaf/synth/SynthMenuBarUI.java | 4 -- .../swing/plaf/synth/SynthMenuItemUI.java | 9 ---- .../javax/swing/plaf/synth/SynthMenuUI.java | 9 ---- .../swing/plaf/synth/SynthOptionPaneUI.java | 6 --- .../javax/swing/plaf/synth/SynthPanelUI.java | 4 -- .../swing/plaf/synth/SynthPopupMenuUI.java | 4 -- .../swing/plaf/synth/SynthProgressBarUI.java | 5 --- .../swing/plaf/synth/SynthRootPaneUI.java | 4 -- .../swing/plaf/synth/SynthScrollBarUI.java | 11 ----- .../swing/plaf/synth/SynthScrollPaneUI.java | 5 --- .../swing/plaf/synth/SynthSeparatorUI.java | 5 --- .../javax/swing/plaf/synth/SynthSliderUI.java | 16 ------- .../swing/plaf/synth/SynthSpinnerUI.java | 4 -- .../plaf/synth/SynthSplitPaneDivider.java | 1 - .../swing/plaf/synth/SynthSplitPaneUI.java | 7 ---- .../swing/plaf/synth/SynthTabbedPaneUI.java | 16 ------- .../swing/plaf/synth/SynthTableHeaderUI.java | 4 -- .../javax/swing/plaf/synth/SynthTableUI.java | 4 -- .../swing/plaf/synth/SynthTextAreaUI.java | 3 -- .../swing/plaf/synth/SynthTextFieldUI.java | 3 -- .../swing/plaf/synth/SynthToolBarUI.java | 13 ------ .../swing/plaf/synth/SynthToolTipUI.java | 5 --- .../javax/swing/plaf/synth/SynthTreeUI.java | 11 ----- .../swing/plaf/synth/SynthViewportUI.java | 4 -- 39 files changed, 11 insertions(+), 242 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthArrowButton.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthArrowButton.java index e4766bb12c4..71a136f0d63 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthArrowButton.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthArrowButton.java @@ -139,7 +139,6 @@ class SynthArrowButton extends JButton implements SwingConstants, UIResource { } } - context.dispose(); return dim; } } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthBorder.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthBorder.java index 8dcbd6ff36c..57a868c7b3a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthBorder.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthBorder.java @@ -61,7 +61,6 @@ class SynthBorder extends AbstractBorder implements UIResource { return; } ui.paintBorder(context, g, x, y, width, height); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthButtonUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthButtonUI.java index a85cf146849..379bcd9a10a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthButtonUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthButtonUI.java @@ -105,7 +105,6 @@ public class SynthButtonUI extends BasicButtonUI implements } } - context.dispose(); } /** @@ -125,7 +124,6 @@ public class SynthButtonUI extends BasicButtonUI implements SynthContext context = getContext(b, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -226,7 +224,6 @@ public class SynthButtonUI extends BasicButtonUI implements else { baseline = textRect.y + fm.getAscent(); } - context.dispose(); return baseline; } @@ -253,7 +250,6 @@ public class SynthButtonUI extends BasicButtonUI implements SynthLookAndFeel.update(context, g); paintBackground(context, g, c); paint(context, g); - context.dispose(); } /** @@ -270,7 +266,6 @@ public class SynthButtonUI extends BasicButtonUI implements SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -321,7 +316,6 @@ public class SynthButtonUI extends BasicButtonUI implements protected Icon getDefaultIcon(AbstractButton b) { SynthContext context = getContext(b); Icon icon = context.getStyle().getIcon(context, getPropertyPrefix() + "icon"); - context.dispose(); return icon; } @@ -473,7 +467,6 @@ public class SynthButtonUI extends BasicButtonUI implements b.getVerticalTextPosition(), b.getIconTextGap(), b.getDisplayedMnemonicIndex()); - ss.dispose(); return size; } @@ -494,7 +487,6 @@ public class SynthButtonUI extends BasicButtonUI implements b.getVerticalTextPosition(), b.getIconTextGap(), b.getDisplayedMnemonicIndex()); - ss.dispose(); return size; } @@ -516,7 +508,6 @@ public class SynthButtonUI extends BasicButtonUI implements b.getVerticalTextPosition(), b.getIconTextGap(), b.getDisplayedMnemonicIndex()); - ss.dispose(); return size; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthColorChooserUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthColorChooserUI.java index 72ab2b09a16..4f67bd86d3e 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthColorChooserUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthColorChooserUI.java @@ -65,7 +65,6 @@ public class SynthColorChooserUI extends BasicColorChooserUI implements SynthContext context = getContext(chooser, ENABLED); AbstractColorChooserPanel[] panels = (AbstractColorChooserPanel[]) context.getStyle().get(context, "ColorChooser.panels"); - context.dispose(); if (panels == null) { panels = ColorChooserComponentFactory.getDefaultChooserPanels(); @@ -85,7 +84,6 @@ public class SynthColorChooserUI extends BasicColorChooserUI implements private void updateStyle(JComponent c) { SynthContext context = getContext(c, ENABLED); style = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); } /** @@ -96,7 +94,6 @@ public class SynthColorChooserUI extends BasicColorChooserUI implements SynthContext context = getContext(chooser, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; super.uninstallDefaults(); } @@ -155,7 +152,6 @@ public class SynthColorChooserUI extends BasicColorChooserUI implements context.getPainter().paintColorChooserBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -172,7 +168,6 @@ public class SynthColorChooserUI extends BasicColorChooserUI implements SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java index 8734d55806d..42ddb3b230a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java @@ -144,7 +144,6 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements forceOpaque = style.getBoolean(context, "ComboBox.forceOpaque", false); } - context.dispose(); if(listBox != null) { SynthLookAndFeel.updateStyles(listBox); @@ -182,7 +181,6 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements SynthContext context = getContext(comboBox, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -323,7 +321,6 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements context.getPainter().paintComboBoxBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -340,7 +337,6 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthContext.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthContext.java index 64b6e536f79..164dc0c265f 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthContext.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthContext.java @@ -24,8 +24,6 @@ */ package javax.swing.plaf.synth; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; import javax.swing.JComponent; /** @@ -40,7 +38,6 @@ import javax.swing.JComponent; * @author Scott Violet */ public class SynthContext { - private static final Queue queue = new ConcurrentLinkedQueue<>(); private JComponent component; private Region region; @@ -54,19 +51,15 @@ public class SynthContext { static SynthContext getContext(JComponent component, Region region, SynthStyle style, int state) { - SynthContext context = queue.poll(); - if (context == null) { - context = new SynthContext(); - } - context.reset(component, region, style, state); + SynthContext context = new SynthContext(); + context.component = component; + context.region = region; + context.style = style; + context.state = state; return context; } - static void releaseContext(SynthContext context) { - queue.offer(context); - } - - SynthContext() { + private SynthContext() { } /** @@ -86,7 +79,11 @@ public class SynthContext { throw new NullPointerException( "You must supply a non-null component, region and style"); } - reset(component, region, style, state); + + this.component = component; + this.region = region; + this.style = style; + this.state = state; } @@ -146,23 +143,6 @@ public class SynthContext { return state; } - /** - * Resets the state of the Context. - */ - void reset(JComponent component, Region region, SynthStyle style, - int state) { - this.component = component; - this.region = region; - this.style = style; - this.state = state; - } - - void dispose() { - this.component = null; - this.style = null; - releaseContext(this); - } - /** * Convenience method to get the Painter from the current SynthStyle. * This will NEVER return null. diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDefaultLookup.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDefaultLookup.java index 0e5a6478aef..ba1927bb948 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDefaultLookup.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDefaultLookup.java @@ -41,7 +41,6 @@ class SynthDefaultLookup extends DefaultLookup { } SynthContext context = ((SynthUI)ui).getContext(c); Object value = context.getStyle().get(context, key); - context.dispose(); return value; } } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopIconUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopIconUI.java index 8da1fe0cf3b..e5463beca23 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopIconUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopIconUI.java @@ -121,7 +121,6 @@ public class SynthDesktopIconUI extends BasicDesktopIconUI private void updateStyle(JComponent c) { SynthContext context = getContext(c, ENABLED); style = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); } /** @@ -131,7 +130,6 @@ public class SynthDesktopIconUI extends BasicDesktopIconUI protected void uninstallDefaults() { SynthContext context = getContext(desktopIcon, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -171,7 +169,6 @@ public class SynthDesktopIconUI extends BasicDesktopIconUI context.getPainter().paintDesktopIconBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -188,7 +185,6 @@ public class SynthDesktopIconUI extends BasicDesktopIconUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java index f7b370eb35b..9702fa980ff 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java @@ -119,7 +119,6 @@ public class SynthDesktopPaneUI extends BasicDesktopPaneUI implements uninstallKeyboardActions(); installKeyboardActions(); } - context.dispose(); } /** @@ -143,7 +142,6 @@ public class SynthDesktopPaneUI extends BasicDesktopPaneUI implements SynthContext context = getContext(desktop, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; if (taskBar != null) { @@ -460,7 +458,6 @@ public class SynthDesktopPaneUI extends BasicDesktopPaneUI implements context.getPainter().paintDesktopPaneBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -477,7 +474,6 @@ public class SynthDesktopPaneUI extends BasicDesktopPaneUI implements SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthEditorPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthEditorPaneUI.java index 69489197d6a..ffaeece02fb 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthEditorPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthEditorPaneUI.java @@ -83,7 +83,6 @@ public class SynthEditorPaneUI extends BasicEditorPaneUI implements SynthUI { c.putClientProperty("caretAspectRatio", null); style.uninstallDefaults(context); - context.dispose(); style = null; Object clientProperty = @@ -127,7 +126,6 @@ public class SynthEditorPaneUI extends BasicEditorPaneUI implements SynthUI { installKeyboardActions(); } } - context.dispose(); } /** @@ -165,7 +163,6 @@ public class SynthEditorPaneUI extends BasicEditorPaneUI implements SynthUI { SynthLookAndFeel.update(context, g); paintBackground(context, g, c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthInternalFrameTitlePane.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthInternalFrameTitlePane.java index 92ad059085d..a7413a5577d 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthInternalFrameTitlePane.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthInternalFrameTitlePane.java @@ -138,7 +138,6 @@ class SynthInternalFrameTitlePane extends BasicInternalFrameTitlePane } } } - context.dispose(); } protected void installDefaults() { @@ -149,7 +148,6 @@ class SynthInternalFrameTitlePane extends BasicInternalFrameTitlePane protected void uninstallDefaults() { SynthContext context = getContext(this, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; JInternalFrame.JDesktopIcon di = frame.getDesktopIcon(); if(di != null && di.getComponentPopupMenu() == systemPopupMenu) { @@ -235,7 +233,6 @@ class SynthInternalFrameTitlePane extends BasicInternalFrameTitlePane context.getPainter().paintInternalFrameTitlePaneBackground(context, g, 0, 0, getWidth(), getHeight()); paint(context, g); - context.dispose(); } protected void paint(SynthContext context, Graphics g) { @@ -321,7 +318,6 @@ class SynthInternalFrameTitlePane extends BasicInternalFrameTitlePane SynthContext context = getContext(this); LayoutManager lm = (LayoutManager)style.get(context, "InternalFrameTitlePane.titlePaneLayout"); - context.dispose(); return (lm != null) ? lm : new SynthTitlePaneLayout(); } @@ -362,7 +358,6 @@ class SynthInternalFrameTitlePane extends BasicInternalFrameTitlePane Image.SCALE_SMOOTH)); } } - context.dispose(); menuButton.setIcon(frameIcon); } @@ -433,7 +428,6 @@ class SynthInternalFrameTitlePane extends BasicInternalFrameTitlePane Insets insets = getInsets(); height += insets.top + insets.bottom; width += insets.left + insets.right; - context.dispose(); return new Dimension(width, height); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthInternalFrameUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthInternalFrameUI.java index 8ed25333234..a11e7549d5d 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthInternalFrameUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthInternalFrameUI.java @@ -118,7 +118,6 @@ public class SynthInternalFrameUI extends BasicInternalFrameUI installKeyboardActions(); } } - context.dispose(); } /** @@ -128,7 +127,6 @@ public class SynthInternalFrameUI extends BasicInternalFrameUI protected void uninstallDefaults() { SynthContext context = getContext(frame, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; if(frame.getLayout() == internalFrameLayout) { frame.setLayout(null); @@ -216,7 +214,6 @@ public class SynthInternalFrameUI extends BasicInternalFrameUI context.getPainter().paintInternalFrameBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -233,7 +230,6 @@ public class SynthInternalFrameUI extends BasicInternalFrameUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLabelUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLabelUI.java index 22e57e5e4a8..4d5b900a931 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLabelUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLabelUI.java @@ -67,7 +67,6 @@ public class SynthLabelUI extends BasicLabelUI implements SynthUI { void updateStyle(JLabel c) { SynthContext context = getContext(c, ENABLED); style = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); } /** @@ -78,7 +77,6 @@ public class SynthLabelUI extends BasicLabelUI implements SynthUI { SynthContext context = getContext(c, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -150,7 +148,6 @@ public class SynthLabelUI extends BasicLabelUI implements SynthUI { else { baseline = textRect.y + fm.getAscent(); } - context.dispose(); return baseline; } @@ -174,7 +171,6 @@ public class SynthLabelUI extends BasicLabelUI implements SynthUI { context.getPainter().paintLabelBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -191,7 +187,6 @@ public class SynthLabelUI extends BasicLabelUI implements SynthUI { SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -242,7 +237,6 @@ public class SynthLabelUI extends BasicLabelUI implements SynthUI { label.getVerticalTextPosition(), label.getIconTextGap(), label.getDisplayedMnemonicIndex()); - context.dispose(); return size; } @@ -263,7 +257,6 @@ public class SynthLabelUI extends BasicLabelUI implements SynthUI { label.getVerticalTextPosition(), label.getIconTextGap(), label.getDisplayedMnemonicIndex()); - context.dispose(); return size; } @@ -284,7 +277,6 @@ public class SynthLabelUI extends BasicLabelUI implements SynthUI { label.getVerticalTextPosition(), label.getIconTextGap(), label.getDisplayedMnemonicIndex()); - context.dispose(); return size; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthListUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthListUI.java index 121ddb5cb81..b7e96f611e9 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthListUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthListUI.java @@ -75,7 +75,6 @@ public class SynthListUI extends BasicListUI SynthLookAndFeel.update(context, g); context.getPainter().paintListBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); - context.dispose(); paint(g, c); } @@ -162,7 +161,6 @@ public class SynthListUI extends BasicListUI installKeyboardActions(); } } - context.dispose(); } /** @@ -175,7 +173,6 @@ public class SynthListUI extends BasicListUI SynthContext context = getContext(list, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java index 3998b354ccb..74b0cd2e006 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java @@ -976,7 +976,6 @@ public class SynthLookAndFeel extends BasicLookAndFeel { if (currBG != null && !currBG.equals(lastBG)) { comp.repaint(); } - context.dispose(); } } } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuBarUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuBarUI.java index 1f096646495..77c7a819074 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuBarUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuBarUI.java @@ -83,7 +83,6 @@ public class SynthMenuBarUI extends BasicMenuBarUI installKeyboardActions(); } } - context.dispose(); } /** @@ -94,7 +93,6 @@ public class SynthMenuBarUI extends BasicMenuBarUI SynthContext context = getContext(menuBar, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -143,7 +141,6 @@ public class SynthMenuBarUI extends BasicMenuBarUI context.getPainter().paintMenuBarBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -160,7 +157,6 @@ public class SynthMenuBarUI extends BasicMenuBarUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuItemUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuItemUI.java index 956f76f1fb3..9e07c376675 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuItemUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuItemUI.java @@ -124,13 +124,11 @@ public class SynthMenuItemUI extends BasicMenuItemUI implements installKeyboardActions(); } } - context.dispose(); SynthContext accContext = getContext(mi, Region.MENU_ITEM_ACCELERATOR, ENABLED); accStyle = SynthLookAndFeel.updateStyle(accContext, this); - accContext.dispose(); } /** @@ -140,13 +138,11 @@ public class SynthMenuItemUI extends BasicMenuItemUI implements protected void uninstallDefaults() { SynthContext context = getContext(menuItem, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; SynthContext accContext = getContext(menuItem, Region.MENU_ITEM_ACCELERATOR, ENABLED); accStyle.uninstallDefaults(accContext); - accContext.dispose(); accStyle = null; super.uninstallDefaults(); @@ -218,8 +214,6 @@ public class SynthMenuItemUI extends BasicMenuItemUI implements defaultTextIconGap, acceleratorDelimiter, MenuItemLayoutHelper.useCheckAndArrow(menuItem), getPropertyPrefix()); - context.dispose(); - accContext.dispose(); return value; } @@ -243,7 +237,6 @@ public class SynthMenuItemUI extends BasicMenuItemUI implements SynthLookAndFeel.update(context, g); paintBackground(context, g, c); paint(context, g); - context.dispose(); } /** @@ -260,7 +253,6 @@ public class SynthMenuItemUI extends BasicMenuItemUI implements SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -280,7 +272,6 @@ public class SynthMenuItemUI extends BasicMenuItemUI implements Icon arrowIcon = style.getIcon(context, prefix + ".arrowIcon"); SynthGraphicsUtils.paint(context, accContext, g, checkIcon, arrowIcon, acceleratorDelimiter, defaultTextIconGap, getPropertyPrefix()); - accContext.dispose(); } void paintBackground(SynthContext context, Graphics g, JComponent c) { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuUI.java index 7bb66a25c93..be1bd34cab1 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuUI.java @@ -110,13 +110,11 @@ public class SynthMenuUI extends BasicMenuUI installKeyboardActions(); } } - context.dispose(); SynthContext accContext = getContext(mi, Region.MENU_ITEM_ACCELERATOR, ENABLED); accStyle = SynthLookAndFeel.updateStyle(accContext, this); - accContext.dispose(); } /** @@ -140,13 +138,11 @@ public class SynthMenuUI extends BasicMenuUI protected void uninstallDefaults() { SynthContext context = getContext(menuItem, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; SynthContext accContext = getContext(menuItem, Region.MENU_ITEM_ACCELERATOR, ENABLED); accStyle.uninstallDefaults(accContext); - accContext.dispose(); accStyle = null; super.uninstallDefaults(); @@ -218,8 +214,6 @@ public class SynthMenuUI extends BasicMenuUI defaultTextIconGap, acceleratorDelimiter, MenuItemLayoutHelper.useCheckAndArrow(menuItem), getPropertyPrefix()); - context.dispose(); - accContext.dispose(); return value; } @@ -243,7 +237,6 @@ public class SynthMenuUI extends BasicMenuUI context.getPainter().paintMenuBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -260,7 +253,6 @@ public class SynthMenuUI extends BasicMenuUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -279,7 +271,6 @@ public class SynthMenuUI extends BasicMenuUI Icon arrowIcon = style.getIcon(context, prefix + ".arrowIcon"); SynthGraphicsUtils.paint(context, accContext, g, checkIcon, arrowIcon, acceleratorDelimiter, defaultTextIconGap, getPropertyPrefix()); - accContext.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthOptionPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthOptionPaneUI.java index de6f2a7135e..b09ed3a7709 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthOptionPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthOptionPaneUI.java @@ -88,7 +88,6 @@ public class SynthOptionPaneUI extends BasicOptionPaneUI implements installKeyboardActions(); } } - context.dispose(); } /** @@ -99,7 +98,6 @@ public class SynthOptionPaneUI extends BasicOptionPaneUI implements SynthContext context = getContext(optionPane, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -125,7 +123,6 @@ public class SynthOptionPaneUI extends BasicOptionPaneUI implements SynthContext context = getContext(optionPane, ENABLED); optionPane.add(Box.createVerticalStrut(context.getStyle(). getInt(context, "OptionPane.separatorPadding", 6))); - context.dispose(); } optionPane.add(createButtonArea()); optionPane.applyComponentOrientation(optionPane.getComponentOrientation()); @@ -167,7 +164,6 @@ public class SynthOptionPaneUI extends BasicOptionPaneUI implements context.getPainter().paintOptionPaneBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -184,7 +180,6 @@ public class SynthOptionPaneUI extends BasicOptionPaneUI implements SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -259,7 +254,6 @@ public class SynthOptionPaneUI extends BasicOptionPaneUI implements SynthContext context = getContext(optionPane, ENABLED); cons.anchor = context.getStyle().getInt(context, "OptionPane.messageAnchor", GridBagConstraints.CENTER); - context.dispose(); cons.insets = new Insets(0,0,3,0); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthPanelUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthPanelUI.java index 73f37ff530b..a9b91b79099 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthPanelUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthPanelUI.java @@ -108,14 +108,12 @@ public class SynthPanelUI extends BasicPanelUI SynthContext context = getContext(p, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } private void updateStyle(JPanel c) { SynthContext context = getContext(c, ENABLED); style = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); } /** @@ -154,7 +152,6 @@ public class SynthPanelUI extends BasicPanelUI context.getPainter().paintPanelBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -171,7 +168,6 @@ public class SynthPanelUI extends BasicPanelUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthPopupMenuUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthPopupMenuUI.java index cbb09f29212..d3f1e25f7ae 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthPopupMenuUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthPopupMenuUI.java @@ -77,7 +77,6 @@ public class SynthPopupMenuUI extends BasicPopupMenuUI installKeyboardActions(); } } - context.dispose(); } /** @@ -97,7 +96,6 @@ public class SynthPopupMenuUI extends BasicPopupMenuUI SynthContext context = getContext(popupMenu, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; if (popupMenu.getLayout() instanceof UIResource) { @@ -150,7 +148,6 @@ public class SynthPopupMenuUI extends BasicPopupMenuUI context.getPainter().paintPopupMenuBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -167,7 +164,6 @@ public class SynthPopupMenuUI extends BasicPopupMenuUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java index f38fea87fb6..743366f4112 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java @@ -118,7 +118,6 @@ public class SynthProgressBarUI extends BasicProgressBarUI } minBarSize = (Dimension)style.get(context, "ProgressBar.minBarSize"); glowWidth = style.getInt(context, "ProgressBar.glowWidth", 0); - context.dispose(); } /** @@ -129,7 +128,6 @@ public class SynthProgressBarUI extends BasicProgressBarUI SynthContext context = getContext(progressBar, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -160,7 +158,6 @@ public class SynthProgressBarUI extends BasicProgressBarUI SynthContext context = getContext(c); Font font = context.getStyle().getFont(context); FontMetrics metrics = progressBar.getFontMetrics(font); - context.dispose(); return (height - metrics.getAscent() - metrics.getDescent()) / 2 + metrics.getAscent(); } @@ -216,7 +213,6 @@ public class SynthProgressBarUI extends BasicProgressBarUI g, 0, 0, c.getWidth(), c.getHeight(), progressBar.getOrientation()); paint(context, g); - context.dispose(); } /** @@ -233,7 +229,6 @@ public class SynthProgressBarUI extends BasicProgressBarUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthRootPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthRootPaneUI.java index 1115fe35551..13244226ba3 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthRootPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthRootPaneUI.java @@ -67,7 +67,6 @@ public class SynthRootPaneUI extends BasicRootPaneUI implements SynthUI { SynthContext context = getContext(root, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -97,7 +96,6 @@ public class SynthRootPaneUI extends BasicRootPaneUI implements SynthUI { installKeyboardActions((JRootPane)c); } } - context.dispose(); } /** @@ -120,7 +118,6 @@ public class SynthRootPaneUI extends BasicRootPaneUI implements SynthUI { context.getPainter().paintRootPaneBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -137,7 +134,6 @@ public class SynthRootPaneUI extends BasicRootPaneUI implements SynthUI { SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollBarUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollBarUI.java index bf86f377412..b93196a9eab 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollBarUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollBarUI.java @@ -129,15 +129,12 @@ public class SynthScrollBarUI extends BasicScrollBarUI installKeyboardActions(); } } - context.dispose(); context = getContext(c, Region.SCROLL_BAR_TRACK, ENABLED); trackStyle = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); context = getContext(c, Region.SCROLL_BAR_THUMB, ENABLED); thumbStyle = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); } /** @@ -165,17 +162,14 @@ public class SynthScrollBarUI extends BasicScrollBarUI protected void uninstallDefaults(){ SynthContext context = getContext(scrollbar, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; context = getContext(scrollbar, Region.SCROLL_BAR_TRACK, ENABLED); trackStyle.uninstallDefaults(context); - context.dispose(); trackStyle = null; context = getContext(scrollbar, Region.SCROLL_BAR_THUMB, ENABLED); thumbStyle.uninstallDefaults(context); - context.dispose(); thumbStyle = null; super.uninstallDefaults(); @@ -222,7 +216,6 @@ public class SynthScrollBarUI extends BasicScrollBarUI SynthContext context = getContext(scrollbar); boolean value = style.getBoolean(context, "ScrollBar.allowsAbsolutePositioning", false); - context.dispose(); return value; } @@ -247,7 +240,6 @@ public class SynthScrollBarUI extends BasicScrollBarUI g, 0, 0, c.getWidth(), c.getHeight(), scrollbar.getOrientation()); paint(context, g); - context.dispose(); } /** @@ -264,7 +256,6 @@ public class SynthScrollBarUI extends BasicScrollBarUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -278,11 +269,9 @@ public class SynthScrollBarUI extends BasicScrollBarUI SynthContext subcontext = getContext(scrollbar, Region.SCROLL_BAR_TRACK); paintTrack(subcontext, g, getTrackBounds()); - subcontext.dispose(); subcontext = getContext(scrollbar, Region.SCROLL_BAR_THUMB); paintThumb(subcontext, g, getThumbBounds()); - subcontext.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollPaneUI.java index 6b3e29602de..8e4601eb85e 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollPaneUI.java @@ -83,7 +83,6 @@ public class SynthScrollPaneUI extends BasicScrollPaneUI context.getPainter().paintScrollPaneBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -100,7 +99,6 @@ public class SynthScrollPaneUI extends BasicScrollPaneUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -150,7 +148,6 @@ public class SynthScrollPaneUI extends BasicScrollPaneUI installKeyboardActions(c); } } - context.dispose(); } /** @@ -178,7 +175,6 @@ public class SynthScrollPaneUI extends BasicScrollPaneUI SynthContext context = getContext(c, ENABLED); style.uninstallDefaults(context); - context.dispose(); if (scrollpane.getViewportBorder() instanceof UIResource) { scrollpane.setViewportBorder(null); @@ -254,7 +250,6 @@ public class SynthScrollPaneUI extends BasicScrollPaneUI } context.getPainter().paintViewportBorder(context, g, x, y, width, height); - context.dispose(); } @Override diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSeparatorUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSeparatorUI.java index a222a428080..b9de6433b47 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSeparatorUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSeparatorUI.java @@ -106,7 +106,6 @@ public class SynthSeparatorUI extends SeparatorUI } } - context.dispose(); } /** @@ -120,7 +119,6 @@ public class SynthSeparatorUI extends SeparatorUI SynthContext context = getContext(c, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -168,7 +166,6 @@ public class SynthSeparatorUI extends SeparatorUI g, 0, 0, c.getWidth(), c.getHeight(), separator.getOrientation()); paint(context, g); - context.dispose(); } /** @@ -185,7 +182,6 @@ public class SynthSeparatorUI extends SeparatorUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -231,7 +227,6 @@ public class SynthSeparatorUI extends SeparatorUI size = new Dimension(insets.left + insets.right, insets.top + insets.bottom + thickness); } - context.dispose(); return size; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSliderUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSliderUI.java index 9c222e1a925..9118fb7569f 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSliderUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSliderUI.java @@ -116,17 +116,14 @@ public class SynthSliderUI extends BasicSliderUI protected void uninstallDefaults(JSlider slider) { SynthContext context = getContext(slider, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; context = getContext(slider, Region.SLIDER_TRACK, ENABLED); sliderTrackStyle.uninstallDefaults(context); - context.dispose(); sliderTrackStyle = null; context = getContext(slider, Region.SLIDER_THUMB, ENABLED); sliderThumbStyle.uninstallDefaults(context); - context.dispose(); sliderThumbStyle = null; } @@ -190,17 +187,14 @@ public class SynthSliderUI extends BasicSliderUI installKeyboardActions(c); } } - context.dispose(); context = getContext(c, Region.SLIDER_TRACK, ENABLED); sliderTrackStyle = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); context = getContext(c, Region.SLIDER_THUMB, ENABLED); sliderThumbStyle = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); } /** @@ -252,14 +246,12 @@ public class SynthSliderUI extends BasicSliderUI SynthContext trackContext = getContext(slider, Region.SLIDER_TRACK); style.getInsets(trackContext, trackInsets); - trackContext.dispose(); if (slider.getOrientation() == JSlider.HORIZONTAL) { int valueHeight = 0; if (paintValue) { SynthContext context = getContext(slider); valueHeight = context.getStyle().getGraphicsUtils(context). getMaximumCharHeight(context); - context.dispose(); } int tickHeight = 0; if (slider.getPaintTicks()) { @@ -287,7 +279,6 @@ public class SynthSliderUI extends BasicSliderUI SynthContext context = getContext(slider); valueHeight = context.getStyle().getGraphicsUtils( context).getMaximumCharHeight(context); - context.dispose(); } int contentHeight = height - insetCache.top - insetCache.bottom; @@ -359,7 +350,6 @@ public class SynthSliderUI extends BasicSliderUI Insets trackInsets = new Insets(0, 0, 0, 0); SynthContext trackContext = getContext(slider, Region.SLIDER_TRACK); style.getInsets(trackContext, trackInsets); - trackContext.dispose(); if (slider.getOrientation() == JSlider.HORIZONTAL) { // Calculate the height of all the subcomponents so we can center @@ -509,7 +499,6 @@ public class SynthSliderUI extends BasicSliderUI trackRect.x = startX + tickRect.width + trackInsets.left; } } - context.dispose(); lastSize = slider.getSize(); } @@ -715,7 +704,6 @@ public class SynthSliderUI extends BasicSliderUI insetCache = newInsets; calculateGeometry(); } - context.dispose(); } /** @@ -774,7 +762,6 @@ public class SynthSliderUI extends BasicSliderUI g, 0, 0, c.getWidth(), c.getHeight(), slider.getOrientation()); paint(context, g); - context.dispose(); } /** @@ -790,7 +777,6 @@ public class SynthSliderUI extends BasicSliderUI public void paint(Graphics g, JComponent c) { SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -835,13 +821,11 @@ public class SynthSliderUI extends BasicSliderUI if (slider.getPaintTrack() && clip.intersects(trackRect)) { SynthContext subcontext = getContext(slider, Region.SLIDER_TRACK); paintTrack(subcontext, g, trackRect); - subcontext.dispose(); } if (clip.intersects(thumbRect)) { SynthContext subcontext = getContext(slider, Region.SLIDER_THUMB); paintThumb(subcontext, g, thumbRect); - subcontext.dispose(); } if (slider.getPaintTicks() && clip.intersects(tickRect)) { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSpinnerUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSpinnerUI.java index a1293dfdadd..2c430e03e82 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSpinnerUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSpinnerUI.java @@ -131,7 +131,6 @@ public class SynthSpinnerUI extends BasicSpinnerUI installKeyboardActions(); } } - context.dispose(); } @@ -151,7 +150,6 @@ public class SynthSpinnerUI extends BasicSpinnerUI SynthContext context = getContext(spinner, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -301,7 +299,6 @@ public class SynthSpinnerUI extends BasicSpinnerUI context.getPainter().paintSpinnerBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } @@ -319,7 +316,6 @@ public class SynthSpinnerUI extends BasicSpinnerUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneDivider.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneDivider.java index c3a203e5237..ab0c0954318 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneDivider.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneDivider.java @@ -81,7 +81,6 @@ class SynthSplitPaneDivider extends BasicSplitPaneDivider { context.getPainter().paintSplitPaneDividerForeground(context, g, 0, 0, getWidth(), getHeight(), splitPane.getOrientation()); - context.dispose(); // super.paint(g2); for (int counter = 0; counter < getComponentCount(); counter++) { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java index 667d6ded258..6c4a1d42901 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java @@ -121,7 +121,6 @@ public class SynthSplitPaneUI extends BasicSplitPaneUI ENABLED); SynthStyle oldDividerStyle = dividerStyle; dividerStyle = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); context = getContext(splitPane, ENABLED); SynthStyle oldStyle = style; @@ -160,7 +159,6 @@ public class SynthSplitPaneUI extends BasicSplitPaneUI divider.setBasicSplitPaneUI(this); splitPane.add(divider, JSplitPane.DIVIDER); } - context.dispose(); } /** @@ -180,12 +178,10 @@ public class SynthSplitPaneUI extends BasicSplitPaneUI SynthContext context = getContext(splitPane, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; context = getContext(splitPane, Region.SPLIT_PANE_DIVIDER, ENABLED); dividerStyle.uninstallDefaults(context); - context.dispose(); dividerStyle = null; super.uninstallDefaults(); @@ -287,7 +283,6 @@ public class SynthSplitPaneUI extends BasicSplitPaneUI context.getPainter().paintSplitPaneBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -304,7 +299,6 @@ public class SynthSplitPaneUI extends BasicSplitPaneUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -338,7 +332,6 @@ public class SynthSplitPaneUI extends BasicSplitPaneUI context.getPainter().paintSplitPaneDragDivider(context, g, x, y, w, h, splitPane.getOrientation()); g.setClip(oldClip); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java index 211e8a2c331..8e59afe9342 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java @@ -154,27 +154,17 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI installKeyboardActions(); } } - context.dispose(); - if (tabContext != null) { - tabContext.dispose(); - } tabContext = getContext(c, Region.TABBED_PANE_TAB, ENABLED); this.tabStyle = SynthLookAndFeel.updateStyle(tabContext, this); tabInsets = tabStyle.getInsets(tabContext, null); - if (tabAreaContext != null) { - tabAreaContext.dispose(); - } tabAreaContext = getContext(c, Region.TABBED_PANE_TAB_AREA, ENABLED); this.tabAreaStyle = SynthLookAndFeel.updateStyle(tabAreaContext, this); tabAreaInsets = tabAreaStyle.getInsets(tabAreaContext, null); - if (tabContentContext != null) { - tabContentContext.dispose(); - } tabContentContext = getContext(c, Region.TABBED_PANE_CONTENT, ENABLED); this.tabContentStyle = SynthLookAndFeel.updateStyle(tabContentContext, this); @@ -207,21 +197,17 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI protected void uninstallDefaults() { SynthContext context = getContext(tabPane, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; tabStyle.uninstallDefaults(tabContext); - tabContext.dispose(); tabContext = null; tabStyle = null; tabAreaStyle.uninstallDefaults(tabAreaContext); - tabAreaContext.dispose(); tabAreaContext = null; tabAreaStyle = null; tabContentStyle.uninstallDefaults(tabContentContext); - tabContentContext.dispose(); tabContentContext = null; tabContentStyle = null; } @@ -374,7 +360,6 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI context.getPainter().paintTabbedPaneBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -424,7 +409,6 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java index 16272ffa819..39acd0e90ea 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java @@ -85,7 +85,6 @@ public class SynthTableHeaderUI extends BasicTableHeaderUI installKeyboardActions(); } } - context.dispose(); } /** @@ -109,7 +108,6 @@ public class SynthTableHeaderUI extends BasicTableHeaderUI SynthContext context = getContext(header, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -142,7 +140,6 @@ public class SynthTableHeaderUI extends BasicTableHeaderUI context.getPainter().paintTableHeaderBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -159,7 +156,6 @@ public class SynthTableHeaderUI extends BasicTableHeaderUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableUI.java index 1e5f522416f..08ac1382015 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableUI.java @@ -189,7 +189,6 @@ public class SynthTableUI extends BasicTableUI installKeyboardActions(); } } - context.dispose(); } /** @@ -220,7 +219,6 @@ public class SynthTableUI extends BasicTableUI } SynthContext context = getContext(table, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -273,7 +271,6 @@ public class SynthTableUI extends BasicTableUI context.getPainter().paintTableBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -299,7 +296,6 @@ public class SynthTableUI extends BasicTableUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTextAreaUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTextAreaUI.java index 33214dad926..affbb6f4ecd 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTextAreaUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTextAreaUI.java @@ -88,7 +88,6 @@ public class SynthTextAreaUI extends BasicTextAreaUI implements SynthUI { getComponent().removeFocusListener(handler); style.uninstallDefaults(context); - context.dispose(); style = null; super.uninstallDefaults(); } @@ -107,7 +106,6 @@ public class SynthTextAreaUI extends BasicTextAreaUI implements SynthUI { installKeyboardActions(); } } - context.dispose(); } /** @@ -142,7 +140,6 @@ public class SynthTextAreaUI extends BasicTextAreaUI implements SynthUI { context.getPainter().paintTextAreaBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTextFieldUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTextFieldUI.java index 6adb7538e88..cf0e83637ef 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTextFieldUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTextFieldUI.java @@ -79,7 +79,6 @@ public class SynthTextFieldUI extends BasicTextFieldUI implements SynthUI { installKeyboardActions(); } } - context.dispose(); } static void updateStyle(JTextComponent comp, SynthContext context, @@ -179,7 +178,6 @@ public class SynthTextFieldUI extends BasicTextFieldUI implements SynthUI { SynthLookAndFeel.update(context, g); paintBackground(context, g, c); paint(context, g); - context.dispose(); } /** @@ -262,7 +260,6 @@ public class SynthTextFieldUI extends BasicTextFieldUI implements SynthUI { getComponent().removeFocusListener(handler); style.uninstallDefaults(context); - context.dispose(); style = null; super.uninstallDefaults(); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolBarUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolBarUI.java index a36117cda20..518c25da5a9 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolBarUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolBarUI.java @@ -98,11 +98,9 @@ public class SynthToolBarUI extends BasicToolBarUI SynthContext context = getContext( c, Region.TOOL_BAR_CONTENT, null, ENABLED); contentStyle = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); context = getContext(c, Region.TOOL_BAR_DRAG_WINDOW, null, ENABLED); dragWindowStyle = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); context = getContext(c, ENABLED); SynthStyle oldStyle = style; @@ -116,7 +114,6 @@ public class SynthToolBarUI extends BasicToolBarUI installKeyboardActions(); } } - context.dispose(); } /** @@ -127,7 +124,6 @@ public class SynthToolBarUI extends BasicToolBarUI SynthContext context = getContext(toolBar, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; handleIcon = null; @@ -135,13 +131,11 @@ public class SynthToolBarUI extends BasicToolBarUI context = getContext(toolBar, Region.TOOL_BAR_CONTENT, contentStyle, ENABLED); contentStyle.uninstallDefaults(context); - context.dispose(); contentStyle = null; context = getContext(toolBar, Region.TOOL_BAR_DRAG_WINDOW, dragWindowStyle, ENABLED); dragWindowStyle.uninstallDefaults(context); - context.dispose(); dragWindowStyle = null; toolBar.setLayout(null); @@ -215,7 +209,6 @@ public class SynthToolBarUI extends BasicToolBarUI g, 0, 0, c.getWidth(), c.getHeight(), toolBar.getOrientation()); paint(context, g); - context.dispose(); } /** @@ -232,7 +225,6 @@ public class SynthToolBarUI extends BasicToolBarUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -289,7 +281,6 @@ public class SynthToolBarUI extends BasicToolBarUI SynthContext subcontext = getContext( toolBar, Region.TOOL_BAR_CONTENT, contentStyle); paintContent(subcontext, g, contentRect); - subcontext.dispose(); } /** @@ -326,7 +317,6 @@ public class SynthToolBarUI extends BasicToolBarUI dragWindow.getOrientation()); context.getPainter().paintToolBarDragWindowBorder(context, g, 0, 0, w, h, dragWindow.getOrientation()); - context.dispose(); } // @@ -383,7 +373,6 @@ public class SynthToolBarUI extends BasicToolBarUI dim.width += insets.left + insets.right; dim.height += insets.top + insets.bottom; - context.dispose(); return dim; } @@ -421,7 +410,6 @@ public class SynthToolBarUI extends BasicToolBarUI dim.width += insets.left + insets.right; dim.height += insets.top + insets.bottom; - context.dispose(); return dim; } @@ -543,7 +531,6 @@ public class SynthToolBarUI extends BasicToolBarUI } } } - context.dispose(); } private boolean isGlue(Component c) { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolTipUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolTipUI.java index dc42debba7d..b73d57ab3dd 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolTipUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolTipUI.java @@ -68,7 +68,6 @@ public class SynthToolTipUI extends BasicToolTipUI private void updateStyle(JComponent c) { SynthContext context = getContext(c, ENABLED); style = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); } /** @@ -78,7 +77,6 @@ public class SynthToolTipUI extends BasicToolTipUI protected void uninstallDefaults(JComponent c) { SynthContext context = getContext(c, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -139,7 +137,6 @@ public class SynthToolTipUI extends BasicToolTipUI context.getPainter().paintToolTipBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -165,7 +162,6 @@ public class SynthToolTipUI extends BasicToolTipUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -218,7 +214,6 @@ public class SynthToolTipUI extends BasicToolTipUI prefSize.height += fm.getHeight(); } } - context.dispose(); return prefSize; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java index 603540c6a58..08194e7e3cf 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java @@ -147,11 +147,9 @@ public class SynthTreeUI extends BasicTreeUI installKeyboardActions(); } } - context.dispose(); context = getContext(tree, Region.TREE_CELL, ENABLED); cellStyle = SynthLookAndFeel.updateStyle(context, this); - context.dispose(); } /** @@ -223,12 +221,10 @@ public class SynthTreeUI extends BasicTreeUI SynthContext context = getContext(tree, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; context = getContext(tree, Region.TREE_CELL, ENABLED); cellStyle.uninstallDefaults(context); - context.dispose(); cellStyle = null; @@ -266,7 +262,6 @@ public class SynthTreeUI extends BasicTreeUI context.getPainter().paintTreeBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -292,7 +287,6 @@ public class SynthTreeUI extends BasicTreeUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** @@ -425,7 +419,6 @@ public class SynthTreeUI extends BasicTreeUI row++; } } - cellContext.dispose(); paintDropLine(g); @@ -743,7 +736,6 @@ public class SynthTreeUI extends BasicTreeUI context.getPainter().paintTreeCellFocus(context, g, 0, 0, getWidth() - imageOffset, getHeight()); } - context.dispose(); } SynthLookAndFeel.resetSelectedUI(); } @@ -785,7 +777,6 @@ public class SynthTreeUI extends BasicTreeUI if (context == null) { context = getContext(tree); SynthGraphicsUtils.paintIcon(expandedIcon, context, g, x, y, w, h); - context.dispose(); } else { SynthGraphicsUtils.paintIcon(expandedIcon, context, g, x, y, w, h); @@ -797,7 +788,6 @@ public class SynthTreeUI extends BasicTreeUI if (context == null) { context = getContext(tree); width = SynthGraphicsUtils.getIconWidth(expandedIcon, context); - context.dispose(); } else { width = SynthGraphicsUtils.getIconWidth(expandedIcon, context); @@ -810,7 +800,6 @@ public class SynthTreeUI extends BasicTreeUI if (context == null) { context = getContext(tree); height = SynthGraphicsUtils.getIconHeight(expandedIcon, context); - context.dispose(); } else { height = SynthGraphicsUtils.getIconHeight(expandedIcon, context); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthViewportUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthViewportUI.java index dc3e6c6e1a1..94483f983d8 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthViewportUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthViewportUI.java @@ -99,7 +99,6 @@ public class SynthViewportUI extends ViewportUI newStyle.installDefaults(context); } this.style = newStyle; - context.dispose(); } /** @@ -128,7 +127,6 @@ public class SynthViewportUI extends ViewportUI protected void uninstallDefaults(JComponent c) { SynthContext context = getContext(c, ENABLED); style.uninstallDefaults(context); - context.dispose(); style = null; } @@ -168,7 +166,6 @@ public class SynthViewportUI extends ViewportUI context.getPainter().paintViewportBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); - context.dispose(); } /** @@ -202,7 +199,6 @@ public class SynthViewportUI extends ViewportUI SynthContext context = getContext(c); paint(context, g); - context.dispose(); } /** From cfa3376da92f7cc8db7e5b1bf705a53a2eaa4743 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 15 Apr 2016 10:25:11 -0700 Subject: [PATCH 088/222] 8154269: Remove unused or unnecessary Xm/Xt files and header includes Reviewed-by: serb, ssadetsky --- .../java.desktop/unix/native/common/awt/awt.h | 4 +- .../unix/native/common/awt/awt_p.h | 7 - .../unix/native/common/awt/extutil.h | 251 ------------- .../native/common/java2d/x11/X11SurfaceData.c | 3 +- .../native/common/java2d/x11/X11SurfaceData.h | 1 - .../unix/native/include/jawt_md.h | 1 - .../native/libawt_headless/awt/VDrawingArea.c | 344 ------------------ .../native/libawt_headless/awt/VDrawingArea.h | 36 -- .../libawt_headless/awt/VDrawingAreaP.h | 79 ---- .../native/libawt_xawt/awt/awt_InputMethod.c | 3 +- .../unix/native/libawt_xawt/awt/awt_Robot.c | 1 - .../unix/native/libawt_xawt/awt/awt_util.c | 1 - .../unix/native/libawt_xawt/xawt/XToolkit.c | 3 +- 13 files changed, 6 insertions(+), 728 deletions(-) delete mode 100644 jdk/src/java.desktop/unix/native/common/awt/extutil.h delete mode 100644 jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingArea.c delete mode 100644 jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingArea.h delete mode 100644 jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingAreaP.h diff --git a/jdk/src/java.desktop/unix/native/common/awt/awt.h b/jdk/src/java.desktop/unix/native/common/awt/awt.h index 0dacab98a40..18a6dee275b 100644 --- a/jdk/src/java.desktop/unix/native/common/awt/awt.h +++ b/jdk/src/java.desktop/unix/native/common/awt/awt.h @@ -35,7 +35,9 @@ #include "debug_util.h" #if !defined(HEADLESS) && !defined(MACOSX) -#include +#include +#include +typedef char Boolean; #endif /* !HEADLESS && !MACOSX */ diff --git a/jdk/src/java.desktop/unix/native/common/awt/awt_p.h b/jdk/src/java.desktop/unix/native/common/awt/awt_p.h index d2d1d74922a..934838c44b1 100644 --- a/jdk/src/java.desktop/unix/native/common/awt/awt_p.h +++ b/jdk/src/java.desktop/unix/native/common/awt/awt_p.h @@ -41,13 +41,6 @@ #include #include #ifndef HEADLESS -#include -#include -#include -#include -#include -#include -#include #include #endif /* !HEADLESS */ #include "awt.h" diff --git a/jdk/src/java.desktop/unix/native/common/awt/extutil.h b/jdk/src/java.desktop/unix/native/common/awt/extutil.h deleted file mode 100644 index ba9f75a7642..00000000000 --- a/jdk/src/java.desktop/unix/native/common/awt/extutil.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 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. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * $Xorg: extutil.h,v 1.3 2000/08/18 04:05:45 coskrey Exp $ - * -Copyright 1989, 1998 The Open Group - -All Rights Reserved. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - * - * Author: Jim Fulton, MIT The Open Group - * - * Xlib Extension-Writing Utilities - * - * This package contains utilities for writing the client API for various - * protocol extensions. THESE INTERFACES ARE NOT PART OF THE X STANDARD AND - * ARE SUBJECT TO CHANGE! - */ -/* $XFree86: xc/include/extensions/extutil.h,v 1.5 2001/01/17 17:53:20 dawes Exp $ */ - -#if defined(__linux__) || defined(MACOSX) - -#ifndef _EXTUTIL_H_ -#define _EXTUTIL_H_ - -/* - * We need to keep a list of open displays since the Xlib display list isn't - * public. We also have to per-display info in a separate block since it isn't - * stored directly in the Display structure. - */ -typedef struct _XExtDisplayInfo { - struct _XExtDisplayInfo *next; /* keep a linked list */ - Display *display; /* which display this is */ - XExtCodes *codes; /* the extension protocol codes */ - XPointer data; /* extra data for extension to use */ -} XExtDisplayInfo; - -typedef struct _XExtensionInfo { - XExtDisplayInfo *head; /* start of list */ - XExtDisplayInfo *cur; /* most recently used */ - int ndisplays; /* number of displays */ -} XExtensionInfo; - -typedef struct _XExtensionHooks { - int (*create_gc)( -#if NeedNestedPrototypes - Display* /* display */, - GC /* gc */, - XExtCodes* /* codes */ -#endif -); - int (*copy_gc)( -#if NeedNestedPrototypes - Display* /* display */, - GC /* gc */, - XExtCodes* /* codes */ -#endif -); - int (*flush_gc)( -#if NeedNestedPrototypes - Display* /* display */, - GC /* gc */, - XExtCodes* /* codes */ -#endif -); - int (*free_gc)( -#if NeedNestedPrototypes - Display* /* display */, - GC /* gc */, - XExtCodes* /* codes */ -#endif -); - int (*create_font)( -#if NeedNestedPrototypes - Display* /* display */, - XFontStruct* /* fs */, - XExtCodes* /* codes */ -#endif -); - int (*free_font)( -#if NeedNestedPrototypes - Display* /* display */, - XFontStruct* /* fs */, - XExtCodes* /* codes */ -#endif -); - int (*close_display)( -#if NeedNestedPrototypes - Display* /* display */, - XExtCodes* /* codes */ -#endif -); - Bool (*wire_to_event)( -#if NeedNestedPrototypes - Display* /* display */, - XEvent* /* re */, - xEvent* /* event */ -#endif -); - Status (*event_to_wire)( -#if NeedNestedPrototypes - Display* /* display */, - XEvent* /* re */, - xEvent* /* event */ -#endif -); - int (*error)( -#if NeedNestedPrototypes - Display* /* display */, - xError* /* err */, - XExtCodes* /* codes */, - int* /* ret_code */ -#endif -); - char *(*error_string)( -#if NeedNestedPrototypes - Display* /* display */, - int /* code */, - XExtCodes* /* codes */, - char* /* buffer */, - int /* nbytes */ -#endif -); -} XExtensionHooks; - -extern XExtensionInfo *XextCreateExtension( -#if NeedFunctionPrototypes - void -#endif -); -extern void XextDestroyExtension( -#if NeedFunctionPrototypes - XExtensionInfo* /* info */ -#endif -); -extern XExtDisplayInfo *XextAddDisplay( -#if NeedFunctionPrototypes - XExtensionInfo* /* extinfo */, - Display* /* dpy */, - char* /* ext_name */, - XExtensionHooks* /* hooks */, - int /* nevents */, - XPointer /* data */ -#endif -); -extern int XextRemoveDisplay( -#if NeedFunctionPrototypes - XExtensionInfo* /* extinfo */, - Display* /* dpy */ -#endif -); -extern XExtDisplayInfo *XextFindDisplay( -#if NeedFunctionPrototypes - XExtensionInfo* /* extinfo */, - Display* /* dpy */ -#endif -); - -#define XextHasExtension(i) ((i) && ((i)->codes)) -#define XextCheckExtension(dpy,i,name,val) \ - if (!XextHasExtension(i)) { XMissingExtension (dpy, name); return val; } -#define XextSimpleCheckExtension(dpy,i,name) \ - if (!XextHasExtension(i)) { XMissingExtension (dpy, name); return; } - - -/* - * helper macros to generate code that is common to all extensions; caller - * should prefix it with static if extension source is in one file; this - * could be a utility function, but have to stack 6 unused arguments for - * something that is called many, many times would be bad. - */ -#define XEXT_GENERATE_FIND_DISPLAY(proc,extinfo,extname,hooks,nev,data) \ -XExtDisplayInfo *proc (Display *dpy) \ -{ \ - XExtDisplayInfo *dpyinfo; \ - if (!extinfo) { if (!(extinfo = XextCreateExtension())) return NULL; } \ - if (!(dpyinfo = XextFindDisplay (extinfo, dpy))) \ - dpyinfo = XextAddDisplay (extinfo,dpy,extname,hooks,nev,data); \ - return dpyinfo; \ -} - -#define XEXT_FIND_DISPLAY_PROTO(proc) \ - XExtDisplayInfo *proc(Display *dpy) - -#define XEXT_GENERATE_CLOSE_DISPLAY(proc,extinfo) \ -int proc (Display *dpy, XExtCodes *codes) \ -{ \ - return XextRemoveDisplay (extinfo, dpy); \ -} - -#define XEXT_CLOSE_DISPLAY_PROTO(proc) \ - int proc(Display *dpy, XExtCodes *codes) - -#define XEXT_GENERATE_ERROR_STRING(proc,extname,nerr,errl) \ -char *proc (Display *dpy, int code, XExtCodes *codes, char *buf, int n) \ -{ \ - code -= codes->first_error; \ - if (code >= 0 && code < nerr) { \ - char tmp[256]; \ - sprintf (tmp, "%s.%d", extname, code); \ - XGetErrorDatabaseText (dpy, "XProtoError", tmp, errl[code], buf, n); \ - return buf; \ - } \ - return (char *)0; \ -} - -#define XEXT_ERROR_STRING_PROTO(proc) \ - char *proc(Display *dpy, int code, XExtCodes *codes, char *buf, int n) -#endif - -#endif /* __linux__ || MACOSX */ diff --git a/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c b/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c index e6597a4723c..07c13f7b7e1 100644 --- a/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c +++ b/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c @@ -270,7 +270,6 @@ Java_sun_java2d_x11_XSurfaceData_initOps(JNIEnv *env, jobject xsd, xsdo->sdOps.Dispose = X11SD_Dispose; xsdo->GetPixmapWithBg = X11SD_GetPixmapWithBg; xsdo->ReleasePixmapWithBg = X11SD_ReleasePixmapWithBg; - xsdo->widget = NULL; if (peer != NULL) { xsdo->drawable = JNU_CallMethodByName(env, &hasException, peer, "getWindow", "()J").j; if (hasException) { @@ -1087,7 +1086,7 @@ static int X11SD_ClipToRoot(SurfaceDataBounds *b, SurfaceDataBounds *bounds, X11SDOps *xsdo) { - Position x1=0, y1=0, x2=0, y2=0; + short x1=0, y1=0, x2=0, y2=0; int tmpx, tmpy; Window tmpchild; diff --git a/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.h b/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.h index 91ad4626a4c..9de747a70e0 100644 --- a/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.h +++ b/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.h @@ -101,7 +101,6 @@ struct _X11SDOps { jboolean isPixmap; jobject peer; Drawable drawable; - Widget widget; GC javaGC; /* used for Java-level GC validation */ GC cachedGC; /* cached for use in X11SD_Unlock() */ jint depth; diff --git a/jdk/src/java.desktop/unix/native/include/jawt_md.h b/jdk/src/java.desktop/unix/native/include/jawt_md.h index b7c2ea749aa..2ba3a8e83cf 100644 --- a/jdk/src/java.desktop/unix/native/include/jawt_md.h +++ b/jdk/src/java.desktop/unix/native/include/jawt_md.h @@ -28,7 +28,6 @@ #include #include -#include #include "jawt.h" #ifdef __cplusplus diff --git a/jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingArea.c b/jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingArea.c deleted file mode 100644 index 712d08409df..00000000000 --- a/jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingArea.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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. - */ - -#ifndef HEADLESS - -#include -#include "VDrawingAreaP.h" - -#endif /* !HEADLESS */ - -#include -#include - -#ifdef __linux__ -/* XXX: Shouldn't be necessary. */ -#include "awt_p.h" -#endif /* __linux__ */ - - -/****************************************************************** - * - * Provides Canvas widget which allows the X11 visual to be - * changed (the Motif DrawingArea restricts the visual to that - * of the parent widget). - * - ******************************************************************/ - - -/****************************************************************** - * - * VDrawingArea Widget Resources - * - ******************************************************************/ - -#ifndef HEADLESS -#define Offset(x) (XtOffsetOf(VDrawingAreaRec, x)) -static XtResource resources[]= -{ - { XtNvisual, XtCVisual, XtRVisual, sizeof(Visual*), - Offset(vdrawing_area.visual), XtRImmediate, CopyFromParent} -}; - - -static void Realize(); -static Boolean SetValues(); -static void Destroy (); - -static XmBaseClassExtRec baseClassExtRec = { - NULL, - NULLQUARK, - XmBaseClassExtVersion, - sizeof(XmBaseClassExtRec), - NULL, /* InitializePrehook */ - NULL, /* SetValuesPrehook */ - NULL, /* InitializePosthook */ - NULL, /* SetValuesPosthook */ - NULL, /* secondaryObjectClass */ - NULL, /* secondaryCreate */ - NULL, /* getSecRes data */ - { 0 }, /* fastSubclass flags */ - NULL, /* getValuesPrehook */ - NULL, /* getValuesPosthook */ - NULL, /* classPartInitPrehook */ - NULL, /* classPartInitPosthook*/ - NULL, /* ext_resources */ - NULL, /* compiled_ext_resources*/ - 0, /* num_ext_resources */ - FALSE, /* use_sub_resources */ - NULL, /* widgetNavigable */ - NULL, /* focusChange */ - NULL /* wrapper_data */ -}; - -VDrawingAreaClassRec vDrawingAreaClassRec = { -{ - /* Core class part */ - - /* superclass */ (WidgetClass)&xmDrawingAreaClassRec, - /* class_name */ "VDrawingArea", - /* widget_size */ sizeof(VDrawingAreaRec), - /* class_initialize */ NULL, - /* class_part_initialize*/ NULL, - /* class_inited */ FALSE, - /* initialize */ NULL, - /* initialize_hook */ NULL, - /* realize */ Realize, - /* actions */ NULL, - /* num_actions */ 0, - /* resources */ resources, - /* num_resources */ XtNumber(resources), - /* xrm_class */ NULLQUARK, - /* compress_motion */ FALSE, - /* compress_exposure */ FALSE, - /* compress_enterleave*/ FALSE, - /* visible_interest */ FALSE, - /* destroy */ Destroy, - /* resize */ XtInheritResize, - /* expose */ XtInheritExpose, - /* set_values */ SetValues, - /* set_values_hook */ NULL, - /* set_values_almost */ XtInheritSetValuesAlmost, - /* get_values_hook */ NULL, - /* accept_focus */ NULL, - /* version */ XtVersion, - /* callback_offsets */ NULL, - /* tm_table */ NULL, - /* query_geometry */ NULL, - /* display_accelerator */ NULL, - /* extension */ NULL - }, - - { /* composite_class fields */ - XtInheritGeometryManager, /* geometry_manager */ - XtInheritChangeManaged, /* change_managed */ - XtInheritInsertChild, /* insert_child */ - XtInheritDeleteChild, /* delete_child */ - NULL, /* extension */ - }, - - { /* constraint_class fields */ - NULL, /* resource list */ - 0, /* num resources */ - 0, /* constraint size */ - NULL, /* init proc */ - NULL, /* destroy proc */ - NULL, /* set values proc */ - NULL, /* extension */ - }, - - { /* manager_class fields */ - XtInheritTranslations, /* translations */ - NULL, /* syn_resources */ - 0, /* num_get_resources */ - NULL, /* syn_cont_resources */ - 0, /* num_get_cont_resources */ - XmInheritParentProcess, /* parent_process */ - NULL, /* extension */ - }, - - { /* drawingArea class */ - /* extension */ NULL - }, - - /* VDrawingArea class part */ - { - /* extension */ NULL - } -}; - -WidgetClass vDrawingAreaClass = (WidgetClass)&vDrawingAreaClassRec; - -static Boolean -SetValues(cw, rw, nw, args, num_args) - Widget cw; - Widget rw; - Widget nw; - ArgList args; - Cardinal *num_args; -{ - VDrawingAreaWidget current = (VDrawingAreaWidget)cw; - VDrawingAreaWidget new_w = (VDrawingAreaWidget)nw; - - if (new_w->vdrawing_area.visual != current->vdrawing_area.visual) { - new_w->vdrawing_area.visual = current->vdrawing_area.visual; -#ifdef DEBUG - fprintf(stdout, "VDrawingArea.SetValues: can't change visual from: visualID=%ld to visualID=%ld\n", - current->vdrawing_area.visual->visualid, - new_w->vdrawing_area.visual->visualid); -#endif - - } - - return (False); -} - -int -FindWindowInList (Window parentWindow, Window *colormap_windows, int count) -{ - int i; - - for (i = 0; i < count; i++) - if (colormap_windows [i] == parentWindow) - return i; - return -1; -} - -static void -Realize(w, value_mask, attributes) - Widget w; - XtValueMask *value_mask; - XSetWindowAttributes *attributes; -{ - Widget parent; - Status status; - Window *colormap_windows; - Window *new_colormap_windows; - int count; - int i; - VDrawingAreaWidget vd = (VDrawingAreaWidget)w; - -#ifdef DEBUG - fprintf(stdout, "VDrawingArea.Realize: visualID=%ld, depth=%d\n", - vd->vdrawing_area.visual->visualid, w->core.depth); -#endif - - /* 4328588: - * Since we have our own Realize() function, we don't execute the one for - * our super-super class, XmManager, and miss the code which checks that - * height and width != 0. I've added that here. -bchristi - */ - if (!XtWidth(w)) XtWidth(w) = 1 ; - if (!XtHeight(w)) XtHeight(w) = 1 ; - - w->core.window = XCreateWindow (XtDisplay (w), XtWindow (w->core.parent), - w->core.x, w->core.y, w->core.width, w->core.height, - 0, w->core.depth, InputOutput, - vd->vdrawing_area.visual, - *value_mask, attributes ); - - /* Need to add this window to the list of Colormap windows */ - parent = XtParent (w); - while ((parent != NULL) && (!(XtIsShell (parent)))) - parent = XtParent (parent); - if (parent == NULL) { - fprintf (stderr, "NO TopLevel widget?!\n"); - return; - } - - status = XGetWMColormapWindows (XtDisplay (w), XtWindow (parent), - &colormap_windows, &count); - - /* If status is zero, add this window and shell to the list - of colormap Windows */ - if (status == 0) { - new_colormap_windows = (Window *) calloc (2, sizeof (Window)); - new_colormap_windows [0] = XtWindow (w); - new_colormap_windows [1] = XtWindow (parent); - XSetWMColormapWindows (XtDisplay (w), XtWindow (parent), - new_colormap_windows, 2); - free (new_colormap_windows); - } else { - /* Check if parent is already in the list */ - int parent_entry = -1; - - if (count > 0) - parent_entry = FindWindowInList (XtWindow (parent), - colormap_windows, count); - if (parent_entry == -1) { /* Parent not in list */ - new_colormap_windows = (Window *) calloc (count + 2, - sizeof (Window)); - new_colormap_windows [0] = XtWindow (w); - new_colormap_windows [1] = XtWindow (parent); - for (i = 0; i < count; i++) - new_colormap_windows [i + 2] = colormap_windows [i]; - XSetWMColormapWindows (XtDisplay (w), XtWindow (parent), - new_colormap_windows, count + 2); - - } else { /* parent already in list, just add new window */ - new_colormap_windows = (Window *) calloc (count + 1, - sizeof (Window)); - new_colormap_windows [0] = XtWindow (w); - for (i = 0; i < count; i++) - new_colormap_windows [i + 1] = colormap_windows [i]; - XSetWMColormapWindows (XtDisplay (w), XtWindow (parent), - new_colormap_windows, count + 1); - } - free (new_colormap_windows); - XFree (colormap_windows); - } - - -} - -static void -Destroy(Widget widget) -{ - Status status; - Widget parent; - Window *colormap_windows; - Window *new_colormap_windows; - int count; - int listEntry; - int i; - int j; - - /* Need to get this window's parent shell first */ - parent = XtParent (widget); - while ((parent != NULL) && (!(XtIsShell (parent)))) - parent = XtParent (parent); - if (parent == NULL) { - fprintf (stderr, "NO TopLevel widget?!\n"); - return; - } - - status = XGetWMColormapWindows (XtDisplay (widget), XtWindow (parent), - &colormap_windows, &count); - - /* If status is zero, then there were no colormap windows for - the parent ?? */ - - if (status == 0) - return; - - /* Remove this window from the list of colormap windows */ - listEntry = FindWindowInList (XtWindow (widget), colormap_windows, - count); - - new_colormap_windows = (Window *) calloc (count - 1, sizeof (Window)); - j = 0; - for (i = 0; i < count; i++) { - if (i == listEntry) - continue; - new_colormap_windows [j] = colormap_windows [i]; - j++; - } - XSetWMColormapWindows (XtDisplay (widget), XtWindow (parent), - new_colormap_windows, count - 1); - free (new_colormap_windows); - XFree (colormap_windows); - -} -#endif /* !HEADLESS */ diff --git a/jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingArea.h b/jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingArea.h deleted file mode 100644 index fe6b67ee530..00000000000 --- a/jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingArea.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 1997, 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. 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. - */ - -#ifndef _VDrawingArea_h_ -#define _VDrawingArea_h_ - -#ifndef HEADLESS -extern WidgetClass vDrawingAreaClass; - -typedef struct _VDrawingAreaClassRec *VDrawingAreaWidgetClass; -typedef struct _VDrawingAreaRec *VDrawingAreaWidget; -#endif /* !HEADLESS */ - -#endif /* !_VDrawingArea_h_ */ diff --git a/jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingAreaP.h b/jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingAreaP.h deleted file mode 100644 index 00864fc50cd..00000000000 --- a/jdk/src/java.desktop/unix/native/libawt_headless/awt/VDrawingAreaP.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved. - * 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. - */ - -#ifndef _VDrawingAreaP_h_ -#define _VDrawingAreaP_h_ - -#include -#include "VDrawingArea.h" - - -/*************************************************************** - * VDrawingArea Widget Data Structures - * - * - **************************************************************/ - -/* Define part class structure */ -typedef struct _VDrawingAreaClass { - XtPointer extension; -} VDrawingAreaClassPart; - -/* Define the full class record */ -typedef struct _VDrawingAreaClassRec { - CoreClassPart core_class; - CompositeClassPart composite_class; - ConstraintClassPart constraint_class; - XmManagerClassPart manager_class; - XmDrawingAreaClassPart drawing_area_class; - VDrawingAreaClassPart vdrawingarea_class; -} VDrawingAreaClassRec; - -/* External definition for class record */ -extern VDrawingAreaClassRec vDrawingAreaClassRec; - -typedef struct { - Visual *visual; -} VDrawingAreaPart; - -/**************************************************************** - * - * Full instance record declaration - * - ****************************************************************/ - -typedef struct _VDrawingAreaRec -{ - CorePart core; - CompositePart composite; - ConstraintPart constraint; - XmManagerPart manager; - XmDrawingAreaPart drawing_area; - VDrawingAreaPart vdrawing_area; -} VDrawingAreaRec; - - - -#endif /* !_VDrawingAreaP_h_ */ diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c index 00d04814e86..e4388cd64a4 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c @@ -40,7 +40,6 @@ #define THROW_OUT_OF_MEMORY_ERROR() \ JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL) -#define SETARG(name, value) XtSetArg(args[argc], name, value); argc++ struct X11InputMethodIDs { jfieldID pData; @@ -590,7 +589,7 @@ static StatusWindow *createStatusWindow( char **mclr; int mccr = 0; char *dsr; - Pixel bg, fg, light, dim; + unsigned long bg, fg, light, dim; int x, y, off_x, off_y, xx, yy; unsigned int w, h, bw, depth; XGCValues values; diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c index c9172a6e5f6..b066844ca74 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c @@ -31,7 +31,6 @@ #include "awt_GraphicsEnv.h" #define XK_MISCELLANY #include -#include #include #include #include diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_util.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_util.c index 261986f9ac0..d61c59b5915 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_util.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_util.c @@ -29,7 +29,6 @@ #include "awt_p.h" #include "color.h" -#include #include #include #include diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c index 3b340914658..db32a22ec6c 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c @@ -354,7 +354,6 @@ JNIEXPORT void JNICALL Java_java_awt_Dialog_initIDs (JNIEnv *env, jclass cls) static void waitForEvents(JNIEnv *, jlong); static void awt_pipe_init(); -static void processOneEvent(XtInputMask iMask); static Boolean performPoll(JNIEnv *, jlong); static void wakeUp(); static void update_poll_timeout(int timeout_control); @@ -614,7 +613,7 @@ static uint32_t get_poll_timeout(jlong nextTaskTime) } /* get_poll_timeout() */ /* - * Waits for X/Xt events to appear on the pipe. Returns only when + * Waits for X events to appear on the pipe. Returns only when * it is likely (but not definite) that there are events waiting to * be processed. * From a7624a0967777411e2e99a85fc9eb2453700262e Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sat, 16 Apr 2016 23:29:11 +0300 Subject: [PATCH 089/222] 8154016: [macosx] Some HiDPI code can be removed Reviewed-by: alexsch, prr --- .../macosx/classes/sun/lwawt/LWWindowPeer.java | 2 +- .../macosx/classes/sun/lwawt/PlatformWindow.java | 6 ------ .../classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java | 9 ++------- .../classes/sun/lwawt/macosx/CPlatformLWWindow.java | 6 ------ .../macosx/classes/sun/lwawt/macosx/CPlatformWindow.java | 6 ------ .../sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java | 6 ------ .../macosx/classes/sun/lwawt/macosx/CWarningWindow.java | 6 +++--- 7 files changed, 6 insertions(+), 35 deletions(-) diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java index 820dc1af2a0..658be0638bb 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java @@ -295,7 +295,7 @@ public class LWWindowPeer if (f == null) { f = DEFAULT_FONT; } - return platformWindow.transformGraphics(new SunGraphics2D(getSurfaceData(), fg, bg, f)); + return new SunGraphics2D(getSurfaceData(), fg, bg, f); } @Override diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java index 81134ef48c4..0e3be9d81a1 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java @@ -130,12 +130,6 @@ public interface PlatformWindow { */ public void setSizeConstraints(int minW, int minH, int maxW, int maxH); - /** - * Transforms the given Graphics object according to the native - * implementation traits (insets, etc.). - */ - public Graphics transformGraphics(Graphics g); - /* * Installs the images for particular window. */ diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java index b2e7466b817..d7c6d2903f6 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java @@ -31,7 +31,6 @@ import java.awt.event.FocusEvent; import sun.java2d.SurfaceData; import sun.java2d.opengl.CGLLayer; import sun.lwawt.LWWindowPeer; -import sun.lwawt.LWWindowPeer.PeerType; import sun.lwawt.PlatformWindow; import sun.util.logging.PlatformLogger; @@ -40,7 +39,8 @@ import sun.util.logging.PlatformLogger; */ public class CPlatformEmbeddedFrame implements PlatformWindow { - private static final PlatformLogger focusLogger = PlatformLogger.getLogger("sun.lwawt.macosx.focus.CPlatformEmbeddedFrame"); + private static final PlatformLogger focusLogger = PlatformLogger.getLogger( + "sun.lwawt.macosx.focus.CPlatformEmbeddedFrame"); private CGLLayer windowLayer; private LWWindowPeer peer; @@ -161,11 +161,6 @@ public class CPlatformEmbeddedFrame implements PlatformWindow { @Override public void setSizeConstraints(int minW, int minH, int maxW, int maxH) {} - @Override - public Graphics transformGraphics(Graphics g) { - return g; - } - @Override public void updateIconImages() {} diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java index 71bb436dff3..a056df5cc10 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java @@ -27,7 +27,6 @@ package sun.lwawt.macosx; import java.awt.Font; import java.awt.FontMetrics; -import java.awt.Graphics; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Insets; @@ -152,11 +151,6 @@ public class CPlatformLWWindow extends CPlatformWindow { public void updateFocusableWindowState() { } - @Override - public Graphics transformGraphics(Graphics g) { - return null; - } - @Override public void setAlwaysOnTop(boolean isAlwaysOnTop) { } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index 835f01a5eca..f0d0a22b3bc 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -740,12 +740,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo setStyleBits(SHOULD_BECOME_KEY | SHOULD_BECOME_MAIN, isFocusable); // set both bits at once } - @Override - public Graphics transformGraphics(Graphics g) { - // is this where we can inject a transform for HiDPI? - return g; - } - @Override public void setAlwaysOnTop(boolean isAlwaysOnTop) { setStyleBits(ALWAYS_ON_TOP, isAlwaysOnTop); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java index e577f286a91..2312fbb94be 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java @@ -27,7 +27,6 @@ package sun.lwawt.macosx; import java.awt.Font; import java.awt.FontMetrics; -import java.awt.Graphics; import java.awt.GraphicsDevice; import java.awt.Insets; import java.awt.MenuBar; @@ -170,11 +169,6 @@ public class CViewPlatformEmbeddedFrame implements PlatformWindow { public void setSizeConstraints(int minW, int minH, int maxW, int maxH) { } - @Override - public Graphics transformGraphics(Graphics g) { - return g; - } - @Override public void updateIconImages() { } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java index b2c36705a09..28a4b657e55 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -364,8 +364,8 @@ public final class CWarningWindow extends CPlatformWindow return null; } - return transformGraphics(new SunGraphics2D(sd, SystemColor.windowText, - SystemColor.window, ownerWindow.getFont())); + return new SunGraphics2D(sd, SystemColor.windowText, SystemColor.window, + ownerWindow.getFont()); } From 0aee9fb36835dd255359debb5b7ae93331967888 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sat, 16 Apr 2016 23:36:45 +0300 Subject: [PATCH 090/222] 8141544: The interface sun.swing.UIClientPropertyKey can be made public Reviewed-by: alexsch --- .../plaf/windows/AnimationController.java | 3 +- .../share/classes/javax/swing/JComponent.java | 2 - .../swing/UIClientPropertyKey.java | 17 +-- .../sun/swing/StringUIClientPropertyKey.java | 4 +- .../UIClientPropertyKeyTest.java | 113 ++++++++++++++++++ 5 files changed, 126 insertions(+), 13 deletions(-) rename jdk/src/java.desktop/share/classes/{sun => javax}/swing/UIClientPropertyKey.java (76%) create mode 100644 jdk/test/javax/swing/ClientProperty/UIClientPropertyKeyTest/UIClientPropertyKeyTest.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/AnimationController.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/AnimationController.java index dab22fd293e..eb47262b29c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/AnimationController.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/AnimationController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,6 @@ import javax.swing.*; -import sun.swing.UIClientPropertyKey; import com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.TMSchema.State.*; import com.sun.java.swing.plaf.windows.TMSchema.Part; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java index dd64b77df1d..56d1df019ba 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java @@ -36,7 +36,6 @@ import java.util.Set; import java.awt.*; import java.awt.event.*; -import java.awt.peer.LightweightPeer; import java.applet.Applet; @@ -57,7 +56,6 @@ import javax.accessibility.*; import sun.awt.AWTAccessor; import sun.awt.SunToolkit; import sun.swing.SwingUtilities2; -import sun.swing.UIClientPropertyKey; /** * The base class for all Swing components except top-level containers. diff --git a/jdk/src/java.desktop/share/classes/sun/swing/UIClientPropertyKey.java b/jdk/src/java.desktop/share/classes/javax/swing/UIClientPropertyKey.java similarity index 76% rename from jdk/src/java.desktop/share/classes/sun/swing/UIClientPropertyKey.java rename to jdk/src/java.desktop/share/classes/javax/swing/UIClientPropertyKey.java index 6ec361cbf45..8aa2bf393fc 100644 --- a/jdk/src/java.desktop/share/classes/sun/swing/UIClientPropertyKey.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/UIClientPropertyKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,18 +23,19 @@ * questions. */ -package sun.swing; +package javax.swing; /** - * This interface is used only for tagging keys for client properties - * for {@code JComponent} set by UI which needs to be cleared on {@literal L&F} + * This interface is used only for tagging keys for client properties for + * {@code JComponent} set by UI which needs to be cleared on {@literal L&F} * change and serialization. - * - * All such keys are removed from client properties in {@code - * JComponent.setUI()} method after uninstalling old UI and before - * intalling the new one. They are also removed prior to serialization. + *

    + * All such keys are removed from client properties in + * {@code JComponent.setUI()} method after uninstalling old UI and before + * installing the new one. They are also removed prior to serialization. * * @author Igor Kushnirskiy + * @since 9 */ public interface UIClientPropertyKey { } diff --git a/jdk/src/java.desktop/share/classes/sun/swing/StringUIClientPropertyKey.java b/jdk/src/java.desktop/share/classes/sun/swing/StringUIClientPropertyKey.java index ea4bb945b1c..7720d484467 100644 --- a/jdk/src/java.desktop/share/classes/sun/swing/StringUIClientPropertyKey.java +++ b/jdk/src/java.desktop/share/classes/sun/swing/StringUIClientPropertyKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.swing; +import javax.swing.UIClientPropertyKey; + /** * An implementation of {@code UIClientPropertyKey} that wraps a {@code String}. * diff --git a/jdk/test/javax/swing/ClientProperty/UIClientPropertyKeyTest/UIClientPropertyKeyTest.java b/jdk/test/javax/swing/ClientProperty/UIClientPropertyKeyTest/UIClientPropertyKeyTest.java new file mode 100644 index 00000000000..499fa0cf3cd --- /dev/null +++ b/jdk/test/javax/swing/ClientProperty/UIClientPropertyKeyTest/UIClientPropertyKeyTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.awt.EventQueue; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import javax.swing.UIClientPropertyKey; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/** + * @test + * @bug 8141544 + */ +public final class UIClientPropertyKeyTest { + + private static Object key = new UIClientPropertyKey() { + }; + + public static void main(final String[] args) throws Exception { + EventQueue.invokeAndWait(UIClientPropertyKeyTest::testSetUI); + EventQueue.invokeAndWait(UIClientPropertyKeyTest::testSerialization); + } + + /** + * UIClientPropertyKey should be removed after deserialization. + */ + private static void testSerialization() { + JComponent comp = new JButton(); + comp.putClientProperty("key1", "value1"); + comp.putClientProperty(key, "value2"); + + comp = serializeDeserialize(comp); + + validate(comp); + } + + /** + * UIClientPropertyKey should be removed on updateUI(). + */ + private static void testSetUI() { + JComponent comp = new JButton(); + comp.putClientProperty("key1", "value1"); + for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { + comp.putClientProperty(key, "value2"); + setLookAndFeel(laf); + SwingUtilities.updateComponentTreeUI(comp); + validate(comp); + } + } + + private static void validate(JComponent comp) { + Object value = comp.getClientProperty("key1"); + if (!value.equals("value1")) { + throw new RuntimeException("Incorrect value: " + value); + } + value = comp.getClientProperty(key); + if (value != null) { + throw new RuntimeException("Incorrect value: " + value); + } + } + + private static void setLookAndFeel(final UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + System.out.println("LookAndFeel: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException | + UnsupportedLookAndFeelException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static JComponent serializeDeserialize(JComponent comp) { + try { + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(byteOut); + out.writeObject(comp); + out.close(); + return (JComponent) new ObjectInputStream(new ByteArrayInputStream( + byteOut.toByteArray())).readObject(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} From ea65ad3102de33a1f6daa63a402e30aa42a3f67a Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sat, 16 Apr 2016 23:39:45 +0300 Subject: [PATCH 091/222] 7102282: TEST_BUG: sun/java2d/OpenGL/GradientPaints.java should be modified Reviewed-by: yan, psadhukhan --- jdk/test/sun/java2d/OpenGL/GradientPaints.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jdk/test/sun/java2d/OpenGL/GradientPaints.java b/jdk/test/sun/java2d/OpenGL/GradientPaints.java index 009ca09bb81..7e8736a96f3 100644 --- a/jdk/test/sun/java2d/OpenGL/GradientPaints.java +++ b/jdk/test/sun/java2d/OpenGL/GradientPaints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,11 @@ /* * @test - * @bug 6521533 6525997 + * @bug 6521533 6525997 7102282 * @summary Verifies that the OGL-accelerated codepaths for GradientPaint, * LinearGradientPaint, and RadialGradientPaint produce results that are * sufficiently close to those produced by the software codepaths. - * @run main/othervm -Dsun.java2d.opengl=True GradientPaints + * @run main/othervm -Dsun.java2d.uiScale=1 -Dsun.java2d.opengl=True GradientPaints * @author campbelc */ From 881e6672230e42d819f7e19b9058691d56aa5cfe Mon Sep 17 00:00:00 2001 From: Prem Balakrishnan Date: Mon, 18 Apr 2016 15:39:29 +0530 Subject: [PATCH 092/222] 8153056: 8152647(duplicate of 6439354) Manual Test always passes Reviewed-by: alexsch, psadhukhan --- .../LookAndFeel/6439354/TitledBorderTest.java | 164 +++++++++++------- 1 file changed, 97 insertions(+), 67 deletions(-) diff --git a/jdk/test/javax/swing/LookAndFeel/6439354/TitledBorderTest.java b/jdk/test/javax/swing/LookAndFeel/6439354/TitledBorderTest.java index f74a14d99ee..118283adf1f 100644 --- a/jdk/test/javax/swing/LookAndFeel/6439354/TitledBorderTest.java +++ b/jdk/test/javax/swing/LookAndFeel/6439354/TitledBorderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6439354 + * @bug 8153056 8152647 6439354 * @summary Verify TitleBorder appearance Color/Visibility for WLAF * @requires (os.family == "windows") * @run main/manual TitledBorderTest @@ -33,6 +33,7 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.concurrent.CountDownLatch; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; @@ -41,7 +42,26 @@ import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.UIManager; -public class TitledBorderTest implements ActionListener { +public class TitledBorderTest { + + public static void main(String args[]) throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + + TitledBorder test = new TitledBorder(latch); + Thread T1 = new Thread(test); + T1.start(); + + // wait for latch to complete + latch.await(); + + if (test.testResult == false) { + throw new RuntimeException("User Clicked Fail!" + + " TitledBorder Not Valid"); + } + } +} + +class TitledBorder implements Runnable { private static GridBagLayout layout; private static JPanel mainControlPanel; @@ -50,88 +70,98 @@ public class TitledBorderTest implements ActionListener { private static JButton passButton; private static JButton failButton; private static JFrame mainFrame; + private final CountDownLatch latch; + public boolean testResult = false; - public static void main(String[] args) throws Exception { - TitledBorderTest titledBorderTest = new TitledBorderTest(); + public TitledBorder(CountDownLatch latch) throws Exception { + this.latch = latch; } - public TitledBorderTest() throws Exception { - createUI(); + @Override + public void run() { + + try { + createUI(); + } catch (Exception ex) { + if (mainFrame != null) { + mainFrame.dispose(); + } + latch.countDown(); + throw new RuntimeException("createUI Failed: " + ex.getMessage()); + } + } public final void createUI() throws Exception { UIManager.setLookAndFeel("com.sun.java.swing.plaf." + "windows.WindowsLookAndFeel"); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + mainFrame = new JFrame("Window LAF TitledBorder Test"); + layout = new GridBagLayout(); + mainControlPanel = new JPanel(layout); + resultButtonPanel = new JPanel(layout); - SwingUtilities.invokeAndWait(() -> { + GridBagConstraints gbc = new GridBagConstraints(); + String instructions + = "INSTRUCTIONS:" + + "\n set Windows Theme to HighContrast#1." + + "\n (ControlPanel->Personalization->High Contrast#1)" + + "\n If Titled Border(Border Line) is visible then test" + + " passes else failed."; - mainFrame = new JFrame("Window LAF TitledBorder Test"); - layout = new GridBagLayout(); - mainControlPanel = new JPanel(layout); - resultButtonPanel = new JPanel(layout); + instructionTextArea = new JTextArea(); + instructionTextArea.setText(instructions); + instructionTextArea.setEnabled(false); + instructionTextArea.setDisabledTextColor(Color.black); + instructionTextArea.setBackground(Color.white); - GridBagConstraints gbc = new GridBagConstraints(); - String instructions - = "INSTRUCTIONS:" - + "\n set Windows Theme to HighContrast#1." - + "\n (ControlPanel->Personalization->High Contrast#1)" - + "\n If Titled Border(Border Line) is visible then test" - + " passes else failed."; + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(instructionTextArea, gbc); - instructionTextArea = new JTextArea(); - instructionTextArea.setText(instructions); - instructionTextArea.setEnabled(false); - instructionTextArea.setDisabledTextColor(Color.black); - instructionTextArea.setBackground(Color.white); + mainControlPanel.setBorder(BorderFactory. + createTitledBorder("Titled Border")); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.fill = GridBagConstraints.HORIZONTAL; - mainControlPanel.add(instructionTextArea, gbc); + passButton = new JButton("Pass"); + passButton.setActionCommand("Pass"); + passButton.addActionListener((ActionEvent e) -> { + System.out.println("Pass Button pressed!"); + testResult = true; + mainFrame.dispose(); + latch.countDown(); - mainControlPanel.setBorder(BorderFactory. - createTitledBorder("Titled Border")); + }); + failButton = new JButton("Fail"); + failButton.setActionCommand("Fail"); + failButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + System.out.println("Fail Button pressed!"); + testResult = false; + mainFrame.dispose(); + latch.countDown(); + } + }); + gbc.gridx = 0; + gbc.gridy = 0; + resultButtonPanel.add(passButton, gbc); + gbc.gridx = 1; + gbc.gridy = 0; + resultButtonPanel.add(failButton, gbc); - passButton = new JButton("Pass"); - passButton.setActionCommand("Pass"); - passButton.addActionListener(TitledBorderTest.this); - failButton = new JButton("Fail"); - failButton.setActionCommand("Fail"); - failButton.addActionListener(TitledBorderTest.this); - gbc.gridx = 0; - gbc.gridy = 0; - resultButtonPanel.add(passButton, gbc); - gbc.gridx = 1; - gbc.gridy = 0; - resultButtonPanel.add(failButton, gbc); + gbc.gridx = 0; + gbc.gridy = 1; + mainControlPanel.add(resultButtonPanel, gbc); - gbc.gridx = 0; - gbc.gridy = 1; - mainControlPanel.add(resultButtonPanel, gbc); - - mainFrame.add(mainControlPanel); - mainFrame.pack(); - mainFrame.setVisible(true); - }); - } - - @Override - public void actionPerformed(ActionEvent evt) { - if (evt.getSource() instanceof JButton) { - JButton btn = (JButton) evt.getSource(); - cleanUp(); - switch (btn.getActionCommand()) { - case "Pass": - break; - case "Fail": - throw new AssertionError("User Clicked Fail!"); + mainFrame.add(mainControlPanel); + mainFrame.pack(); + mainFrame.setVisible(true); } - } - } + }); - private static void cleanUp() { - mainFrame.dispose(); } - } From c536913c218e611cc81f22e92e980ca988414113 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Mon, 18 Apr 2016 10:57:11 -0700 Subject: [PATCH 093/222] 8154403: JRT filesystem loaded by JDK8 with URLClassLoader is not closable since JDK-8147460 Reviewed-by: alanb --- .../classes/jdk/internal/jrtfs/JrtFileSystemProvider.java | 4 ++-- jdk/test/jdk/internal/jrtfs/WithSecurityManager.java | 3 ++- jdk/test/jdk/internal/jrtfs/remote/Main.java | 6 ++++-- .../jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java | 4 +--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java index 19edf480961..746d61a273c 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java @@ -101,10 +101,10 @@ public final class JrtFileSystemProvider extends FileSystemProvider { @Override public FileSystem newFileSystem(URI uri, Map env) throws IOException { + Objects.requireNonNull(env); checkPermission(); checkUri(uri); - - if (env != null && env.containsKey("java.home")) { + if (env.containsKey("java.home")) { return newFileSystem((String)env.get("java.home"), uri, env); } else { return new JrtFileSystem(this, env); diff --git a/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java b/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java index f6d111475ef..81336e20299 100644 --- a/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java +++ b/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java @@ -31,6 +31,7 @@ import java.net.URI; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; public class WithSecurityManager { public static void main(String[] args) throws Exception { @@ -61,7 +62,7 @@ public class WithSecurityManager { // check FileSystems.newFileSystem try { - FileSystems.newFileSystem(URI.create("jrt:/"), null); + FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap()); if (!allow) throw new RuntimeException("access not expected"); } catch (SecurityException se) { if (allow) diff --git a/jdk/test/jdk/internal/jrtfs/remote/Main.java b/jdk/test/jdk/internal/jrtfs/remote/Main.java index 8ef6303526d..9b22c8308d3 100644 --- a/jdk/test/jdk/internal/jrtfs/remote/Main.java +++ b/jdk/test/jdk/internal/jrtfs/remote/Main.java @@ -30,6 +30,7 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import java.util.stream.Stream; /** @@ -69,11 +70,12 @@ public class Main { private static FileSystem createFsWithURLClassloader(String javaHome) throws IOException{ URL url = Paths.get(javaHome, "jrt-fs.jar").toUri().toURL(); URLClassLoader loader = new URLClassLoader(new URL[] { url }); - return FileSystems.newFileSystem(URI.create("jrt:/"), null, loader); + return FileSystems.newFileSystem(URI.create("jrt:/"), + Collections.emptyMap(), + loader); } private static FileSystem createFsByInstalledProvider() throws IOException { return FileSystems.getFileSystem(URI.create("jrt:/")); } } - diff --git a/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java b/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java index 2c3d588369f..7ea315ad5d6 100644 --- a/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java +++ b/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8141609 + * @bug 8141609 8154403 * @summary Verify JDK 8 can use jrt-fs.jar to work with jrt file system. * @run main RemoteRuntimeImageTest */ @@ -63,7 +63,6 @@ public class RemoteRuntimeImageTest { String java = jdk8Path.resolve("bin/java").toAbsolutePath().toString(); String javac = jdk8Path.resolve("bin/javac").toAbsolutePath().toString(); - Files.createDirectories(Paths.get(".", CLASSES_DIR)); String jrtJar = Paths.get(TEST_JAVAHOME, JRTFS_JAR).toAbsolutePath().toString(); @@ -121,4 +120,3 @@ public class RemoteRuntimeImageTest { return version.startsWith("\"1.8"); } } - From 1b0e8a4e73ab119238a4b7507ff55015f1ca5255 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Mon, 18 Apr 2016 19:40:48 +0100 Subject: [PATCH 094/222] 8153353: HPACK implementation Reviewed-by: chegar, rriggs --- .../hpack/BinaryRepresentationWriter.java | 34 + .../hpack/BulkSizeUpdateWriter.java | 78 ++ .../sun/net/httpclient/hpack/Decoder.java | 506 +++++++++++++ .../httpclient/hpack/DecodingCallback.java | 284 ++++++++ .../sun/net/httpclient/hpack/Encoder.java | 429 +++++++++++ .../sun/net/httpclient/hpack/HeaderTable.java | 511 +++++++++++++ .../sun/net/httpclient/hpack/Huffman.java | 676 ++++++++++++++++++ .../sun/net/httpclient/hpack/ISO_8859_1.java | 103 +++ .../hpack/IndexNameValueWriter.java | 101 +++ .../net/httpclient/hpack/IndexedWriter.java | 50 ++ .../net/httpclient/hpack/IntegerReader.java | 142 ++++ .../net/httpclient/hpack/IntegerWriter.java | 117 +++ .../hpack/LiteralNeverIndexedWriter.java | 32 + .../hpack/LiteralWithIndexingWriter.java | 85 +++ .../net/httpclient/hpack/LiteralWriter.java | 32 + .../httpclient/hpack/SizeUpdateWriter.java | 59 ++ .../net/httpclient/hpack/StringReader.java | 111 +++ .../net/httpclient/hpack/StringWriter.java | 126 ++++ .../net/httpclient/hpack/package-info.java | 34 + .../net/httpclient/http2/HpackDriver.java | 40 ++ .../hpack/BinaryPrimitivesTest.java | 347 +++++++++ .../httpclient/hpack/BuffersTestingKit.java | 210 ++++++ .../httpclient/hpack/CircularBufferTest.java | 125 ++++ .../sun/net/httpclient/hpack/DecoderTest.java | 595 +++++++++++++++ .../sun/net/httpclient/hpack/EncoderTest.java | 623 ++++++++++++++++ .../net/httpclient/hpack/HeaderTableTest.java | 375 ++++++++++ .../sun/net/httpclient/hpack/HuffmanTest.java | 623 ++++++++++++++++ .../sun/net/httpclient/hpack/SpecHelper.java | 70 ++ .../sun/net/httpclient/hpack/TestHelper.java | 164 +++++ 29 files changed, 6682 insertions(+) create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BinaryRepresentationWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BulkSizeUpdateWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Decoder.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/DecodingCallback.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Encoder.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Huffman.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/ISO_8859_1.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexNameValueWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexedWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerReader.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralNeverIndexedWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWithIndexingWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/SizeUpdateWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringReader.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringWriter.java create mode 100644 jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/package-info.java create mode 100644 jdk/test/java/net/httpclient/http2/HpackDriver.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BinaryPrimitivesTest.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BuffersTestingKit.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/CircularBufferTest.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/DecoderTest.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/EncoderTest.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HeaderTableTest.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HuffmanTest.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/SpecHelper.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/TestHelper.java diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BinaryRepresentationWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BinaryRepresentationWriter.java new file mode 100644 index 00000000000..de60d58f6ac --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BinaryRepresentationWriter.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +interface BinaryRepresentationWriter { + + boolean write(HeaderTable table, ByteBuffer destination); + + BinaryRepresentationWriter reset(); +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BulkSizeUpdateWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BulkSizeUpdateWriter.java new file mode 100644 index 00000000000..1c064f627f5 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BulkSizeUpdateWriter.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Iterator; + +import static java.util.Objects.requireNonNull; + +final class BulkSizeUpdateWriter implements BinaryRepresentationWriter { + + private final SizeUpdateWriter writer = new SizeUpdateWriter(); + private Iterator maxSizes; + private boolean writing; + private boolean configured; + + BulkSizeUpdateWriter maxHeaderTableSizes(Iterable sizes) { + if (configured) { + throw new IllegalStateException("Already configured"); + } + requireNonNull(sizes, "sizes"); + maxSizes = sizes.iterator(); + configured = true; + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + if (!configured) { + throw new IllegalStateException("Configure first"); + } + while (true) { + if (writing) { + if (!writer.write(table, destination)) { + return false; + } + writing = false; + } else if (maxSizes.hasNext()) { + writing = true; + writer.reset(); + writer.maxHeaderTableSize(maxSizes.next()); + } else { + configured = false; + return true; + } + } + } + + @Override + public BulkSizeUpdateWriter reset() { + maxSizes = null; + writing = false; + configured = false; + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Decoder.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Decoder.java new file mode 100644 index 00000000000..afff906424a --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Decoder.java @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.ProtocolException; +import java.nio.ByteBuffer; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +/** + * Decodes headers from their binary representation. + * + *

    Typical lifecycle looks like this: + * + *

    {@link #Decoder(int) new Decoder} + * ({@link #setMaxCapacity(int) setMaxCapacity}? + * {@link #decode(ByteBuffer, boolean, DecodingCallback) decode})* + * + * @apiNote + * + *

    The design intentions behind Decoder were to facilitate flexible and + * incremental style of processing. + * + *

    {@code Decoder} does not require a complete header block in a single + * {@code ByteBuffer}. The header block can be spread across many buffers of any + * size and decoded one-by-one the way it makes most sense for the user. This + * way also allows not to limit the size of the header block. + * + *

    Headers are delivered to the {@linkplain DecodingCallback callback} as + * soon as they become decoded. Using the callback also gives the user a freedom + * to decide how headers are processed. The callback does not limit the number + * of headers decoded during single decoding operation. + * + * @since 9 + */ +public final class Decoder { + + private static final State[] states = new State[256]; + + static { + // To be able to do a quick lookup, each of 256 possibilities are mapped + // to corresponding states. + // + // We can safely do this since patterns 1, 01, 001, 0001, 0000 are + // Huffman prefixes and therefore are inherently not ambiguous. + // + // I do it mainly for better debugging (to not go each time step by step + // through if...else tree). As for performance win for the decoding, I + // believe is negligible. + for (int i = 0; i < states.length; i++) { + if ((i & 0b1000_0000) == 0b1000_0000) { + states[i] = State.INDEXED; + } else if ((i & 0b1100_0000) == 0b0100_0000) { + states[i] = State.LITERAL_WITH_INDEXING; + } else if ((i & 0b1110_0000) == 0b0010_0000) { + states[i] = State.SIZE_UPDATE; + } else if ((i & 0b1111_0000) == 0b0001_0000) { + states[i] = State.LITERAL_NEVER_INDEXED; + } else if ((i & 0b1111_0000) == 0b0000_0000) { + states[i] = State.LITERAL; + } else { + throw new InternalError(String.valueOf(i)); + } + } + } + + private final HeaderTable table; + + private State state = State.READY; + private final IntegerReader integerReader; + private final StringReader stringReader; + private final StringBuilder name; + private final StringBuilder value; + private int intValue; + private boolean firstValueRead; + private boolean firstValueIndex; + private boolean nameHuffmanEncoded; + private boolean valueHuffmanEncoded; + private int capacity; + + /** + * Constructs a {@code Decoder} with the specified initial capacity of the + * header table. + * + *

    The value has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK (see 4.2. Maximum Table + * Size). + * + * @param capacity + * a non-negative integer + * + * @throws IllegalArgumentException + * if capacity is negative + */ + public Decoder(int capacity) { + setMaxCapacity(capacity); + table = new HeaderTable(capacity); + integerReader = new IntegerReader(); + stringReader = new StringReader(); + name = new StringBuilder(512); + value = new StringBuilder(1024); + } + + /** + * Sets a maximum capacity of the header table. + * + *

    The value has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK (see 4.2. Maximum Table + * Size). + * + * @param capacity + * a non-negative integer + * + * @throws IllegalArgumentException + * if capacity is negative + */ + public void setMaxCapacity(int capacity) { + if (capacity < 0) { + throw new IllegalArgumentException("capacity >= 0: " + capacity); + } + // FIXME: await capacity update if less than what was prior to it + this.capacity = capacity; + } + + /** + * Decodes a header block from the given buffer to the given callback. + * + *

    Suppose a header block is represented by a sequence of {@code + * ByteBuffer}s in the form of {@code Iterator}. And the + * consumer of decoded headers is represented by the callback. Then to + * decode the header block, the following approach might be used: + * + *

    {@code
    +     * while (buffers.hasNext()) {
    +     *     ByteBuffer input = buffers.next();
    +     *     decoder.decode(input, callback, !buffers.hasNext());
    +     * }
    +     * }
    + * + *

    The decoder reads as much as possible of the header block from the + * given buffer, starting at the buffer's position, and increments its + * position to reflect the bytes read. The buffer's mark and limit will not + * be modified. + * + *

    Once the method is invoked with {@code endOfHeaderBlock == true}, the + * current header block is deemed ended, and inconsistencies, if any, are + * reported immediately by throwing an {@code UncheckedIOException}. + * + *

    Each callback method is called only after the implementation has + * processed the corresponding bytes. If the bytes revealed a decoding + * error, the callback method is not called. + * + *

    In addition to exceptions thrown directly by the method, any + * exceptions thrown from the {@code callback} will bubble up. + * + * @apiNote The method asks for {@code endOfHeaderBlock} flag instead of + * returning it for two reasons. The first one is that the user of the + * decoder always knows which chunk is the last. The second one is to throw + * the most detailed exception possible, which might be useful for + * diagnosing issues. + * + * @implNote This implementation is not atomic in respect to decoding + * errors. In other words, if the decoding operation has thrown a decoding + * error, the decoder is no longer usable. + * + * @param headerBlock + * the chunk of the header block, may be empty + * @param endOfHeaderBlock + * true if the chunk is the final (or the only one) in the sequence + * + * @param consumer + * the callback + * @throws UncheckedIOException + * in case of a decoding error + * @throws NullPointerException + * if either headerBlock or consumer are null + */ + public void decode(ByteBuffer headerBlock, boolean endOfHeaderBlock, + DecodingCallback consumer) { + requireNonNull(headerBlock, "headerBlock"); + requireNonNull(consumer, "consumer"); + while (headerBlock.hasRemaining()) { + proceed(headerBlock, consumer); + } + if (endOfHeaderBlock && state != State.READY) { + throw new UncheckedIOException( + new ProtocolException("Unexpected end of header block")); + } + } + + private void proceed(ByteBuffer input, DecodingCallback action) { + switch (state) { + case READY: + resumeReady(input); + break; + case INDEXED: + resumeIndexed(input, action); + break; + case LITERAL: + resumeLiteral(input, action); + break; + case LITERAL_WITH_INDEXING: + resumeLiteralWithIndexing(input, action); + break; + case LITERAL_NEVER_INDEXED: + resumeLiteralNeverIndexed(input, action); + break; + case SIZE_UPDATE: + resumeSizeUpdate(input, action); + break; + default: + throw new InternalError( + "Unexpected decoder state: " + String.valueOf(state)); + } + } + + private void resumeReady(ByteBuffer input) { + int b = input.get(input.position()) & 0xff; // absolute read + State s = states[b]; + switch (s) { + case INDEXED: + integerReader.configure(7); + state = State.INDEXED; + firstValueIndex = true; + break; + case LITERAL: + state = State.LITERAL; + firstValueIndex = (b & 0b0000_1111) != 0; + if (firstValueIndex) { + integerReader.configure(4); + } + break; + case LITERAL_WITH_INDEXING: + state = State.LITERAL_WITH_INDEXING; + firstValueIndex = (b & 0b0011_1111) != 0; + if (firstValueIndex) { + integerReader.configure(6); + } + break; + case LITERAL_NEVER_INDEXED: + state = State.LITERAL_NEVER_INDEXED; + firstValueIndex = (b & 0b0000_1111) != 0; + if (firstValueIndex) { + integerReader.configure(4); + } + break; + case SIZE_UPDATE: + integerReader.configure(5); + state = State.SIZE_UPDATE; + firstValueIndex = true; + break; + default: + throw new InternalError(String.valueOf(s)); + } + if (!firstValueIndex) { + input.get(); // advance, next stop: "String Literal" + } + } + + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 1 | Index (7+) | + // +---+---------------------------+ + // + private void resumeIndexed(ByteBuffer input, DecodingCallback action) { + if (!integerReader.read(input)) { + return; + } + intValue = integerReader.get(); + integerReader.reset(); + try { + HeaderTable.HeaderField f = table.get(intValue); + action.onIndexed(intValue, f.name, f.value); + } finally { + state = State.READY; + } + } + + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 0 | Index (4+) | + // +---+---+-----------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 0 | 0 | + // +---+---+-----------------------+ + // | H | Name Length (7+) | + // +---+---------------------------+ + // | Name String (Length octets) | + // +---+---------------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + private void resumeLiteral(ByteBuffer input, DecodingCallback action) { + if (!completeReading(input)) { + return; + } + try { + if (firstValueIndex) { + HeaderTable.HeaderField f = table.get(intValue); + action.onLiteral(intValue, f.name, value, valueHuffmanEncoded); + } else { + action.onLiteral(name, nameHuffmanEncoded, value, valueHuffmanEncoded); + } + } finally { + cleanUpAfterReading(); + } + } + + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 1 | Index (6+) | + // +---+---+-----------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 1 | 0 | + // +---+---+-----------------------+ + // | H | Name Length (7+) | + // +---+---------------------------+ + // | Name String (Length octets) | + // +---+---------------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + private void resumeLiteralWithIndexing(ByteBuffer input, DecodingCallback action) { + if (!completeReading(input)) { + return; + } + try { + // + // 1. (name, value) will be stored in the table as strings + // 2. Most likely the callback will also create strings from them + // ------------------------------------------------------------------------ + // Let's create those string beforehand (and only once!) to benefit everyone + // + String n; + String v = value.toString(); + if (firstValueIndex) { + HeaderTable.HeaderField f = table.get(intValue); + n = f.name; + action.onLiteralWithIndexing(intValue, n, v, valueHuffmanEncoded); + } else { + n = name.toString(); + action.onLiteralWithIndexing(n, nameHuffmanEncoded, v, valueHuffmanEncoded); + } + table.put(n, v); + } catch (IllegalArgumentException | IllegalStateException e) { + throw new UncheckedIOException( + (IOException) new ProtocolException().initCause(e)); + } finally { + cleanUpAfterReading(); + } + } + + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 1 | Index (4+) | + // +---+---+-----------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 1 | 0 | + // +---+---+-----------------------+ + // | H | Name Length (7+) | + // +---+---------------------------+ + // | Name String (Length octets) | + // +---+---------------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + private void resumeLiteralNeverIndexed(ByteBuffer input, DecodingCallback action) { + if (!completeReading(input)) { + return; + } + try { + if (firstValueIndex) { + HeaderTable.HeaderField f = table.get(intValue); + action.onLiteralNeverIndexed(intValue, f.name, value, valueHuffmanEncoded); + } else { + action.onLiteralNeverIndexed(name, nameHuffmanEncoded, value, valueHuffmanEncoded); + } + } finally { + cleanUpAfterReading(); + } + } + + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 1 | Max size (5+) | + // +---+---------------------------+ + // + private void resumeSizeUpdate(ByteBuffer input, DecodingCallback action) { + if (!integerReader.read(input)) { + return; + } + intValue = integerReader.get(); + assert intValue >= 0; + if (intValue > capacity) { + throw new UncheckedIOException(new ProtocolException( + format("Received capacity exceeds expected: " + + "capacity=%s, expected=%s", intValue, capacity))); + } + integerReader.reset(); + try { + action.onSizeUpdate(intValue); + table.setMaxSize(intValue); + } finally { + state = State.READY; + } + } + + private boolean completeReading(ByteBuffer input) { + if (!firstValueRead) { + if (firstValueIndex) { + if (!integerReader.read(input)) { + return false; + } + intValue = integerReader.get(); + integerReader.reset(); + } else { + if (!stringReader.read(input, name)) { + return false; + } + nameHuffmanEncoded = stringReader.isHuffmanEncoded(); + stringReader.reset(); + } + firstValueRead = true; + return false; + } else { + if (!stringReader.read(input, value)) { + return false; + } + } + valueHuffmanEncoded = stringReader.isHuffmanEncoded(); + stringReader.reset(); + return true; + } + + private void cleanUpAfterReading() { + name.setLength(0); + value.setLength(0); + firstValueRead = false; + state = State.READY; + } + + private enum State { + READY, + INDEXED, + LITERAL_NEVER_INDEXED, + LITERAL, + LITERAL_WITH_INDEXING, + SIZE_UPDATE + } + + HeaderTable getTable() { + return table; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/DecodingCallback.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/DecodingCallback.java new file mode 100644 index 00000000000..d0d1ce5d5d5 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/DecodingCallback.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +/** + * Delivers results of the {@link Decoder#decode(ByteBuffer, boolean, + * DecodingCallback) decoding operation}. + * + *

    Methods of the callback are never called by a decoder with any of the + * arguments being {@code null}. + * + * @apiNote + * + *

    The callback provides methods for all possible binary + * representations. This could be useful for implementing an intermediary, + * logging, debugging, etc. + * + *

    The callback is an interface in order to interoperate with lambdas (in + * the most common use case): + *

    {@code
    + *     DecodingCallback callback = (name, value) -> System.out.println(name + ", " + value);
    + * }
    + * + *

    Names and values are {@link CharSequence}s rather than {@link String}s in + * order to allow users to decide whether or not they need to create objects. A + * {@code CharSequence} might be used in-place, for example, to be appended to + * an {@link Appendable} (e.g. {@link StringBuilder}) and then discarded. + * + *

    That said, if a passed {@code CharSequence} needs to outlast the method + * call, it needs to be copied. + * + * @since 9 + */ +@FunctionalInterface +public interface DecodingCallback { + + /** + * A method the more specific methods of the callback forward their calls + * to. + * + * @param name + * header name + * @param value + * header value + */ + void onDecoded(CharSequence name, CharSequence value); + + /** + * A more finer-grained version of {@link #onDecoded(CharSequence, + * CharSequence)} that also reports on value sensitivity. + * + *

    Value sensitivity must be considered, for example, when implementing + * an intermediary. A {@code value} is sensitive if it was represented as Literal Header + * Field Never Indexed. + * + *

    It is required that intermediaries MUST use the {@linkplain + * Encoder#header(CharSequence, CharSequence, boolean) same representation} + * for encoding this header field in order to protect its value which is not + * to be put at risk by compressing it. + * + * @implSpec + * + *

    The default implementation invokes {@code onDecoded(name, value)}. + * + * @param name + * header name + * @param value + * header value + * @param sensitive + * whether or not the value is sensitive + * + * @see #onLiteralNeverIndexed(int, CharSequence, CharSequence, boolean) + * @see #onLiteralNeverIndexed(CharSequence, boolean, CharSequence, boolean) + */ + default void onDecoded(CharSequence name, CharSequence value, + boolean sensitive) { + onDecoded(name, value); + } + + /** + * An Indexed + * Header Field decoded. + * + * @implSpec + * + *

    The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param index + * index of an entry in the table + * @param name + * header name + * @param value + * header value + */ + default void onIndexed(int index, CharSequence name, CharSequence value) { + onDecoded(name, value, false); + } + + /** + * A Literal + * Header Field without Indexing decoded, where a {@code name} was + * referred by an {@code index}. + * + * @implSpec + * + *

    The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param index + * index of an entry in the table + * @param name + * header name + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteral(int index, CharSequence name, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, false); + } + + /** + * A Literal + * Header Field without Indexing decoded, where both a {@code name} and + * a {@code value} were literal. + * + * @implSpec + * + *

    The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param name + * header name + * @param nameHuffman + * if the {@code name} was Huffman encoded + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteral(CharSequence name, boolean nameHuffman, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, false); + } + + /** + * A Literal + * Header Field Never Indexed decoded, where a {@code name} + * was referred by an {@code index}. + * + * @implSpec + * + *

    The default implementation invokes + * {@code onDecoded(name, value, true)}. + * + * @param index + * index of an entry in the table + * @param name + * header name + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteralNeverIndexed(int index, CharSequence name, + CharSequence value, + boolean valueHuffman) { + onDecoded(name, value, true); + } + + /** + * A Literal + * Header Field Never Indexed decoded, where both a {@code + * name} and a {@code value} were literal. + * + * @implSpec + * + *

    The default implementation invokes + * {@code onDecoded(name, value, true)}. + * + * @param name + * header name + * @param nameHuffman + * if the {@code name} was Huffman encoded + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteralNeverIndexed(CharSequence name, boolean nameHuffman, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, true); + } + + /** + * A Literal + * Header Field with Incremental Indexing decoded, where a {@code name} + * was referred by an {@code index}. + * + * @implSpec + * + *

    The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param index + * index of an entry in the table + * @param name + * header name + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteralWithIndexing(int index, + CharSequence name, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, false); + } + + /** + * A Literal + * Header Field with Incremental Indexing decoded, where both a {@code + * name} and a {@code value} were literal. + * + * @implSpec + * + *

    The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param name + * header name + * @param nameHuffman + * if the {@code name} was Huffman encoded + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteralWithIndexing(CharSequence name, boolean nameHuffman, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, false); + } + + /** + * A Dynamic Table + * Size Update decoded. + * + * @implSpec + * + *

    The default implementation does nothing. + * + * @param capacity + * new capacity of the header table + */ + default void onSizeUpdate(int capacity) { } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Encoder.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Encoder.java new file mode 100644 index 00000000000..75ab8653457 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Encoder.java @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.nio.ReadOnlyBufferException; +import java.util.LinkedList; +import java.util.List; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +/** + * Encodes headers to their binary representation. + * + *

    Typical lifecycle looks like this: + * + *

    {@link #Encoder(int) new Encoder} + * ({@link #setMaxCapacity(int) setMaxCapacity}? + * {@link #encode(ByteBuffer) encode})* + * + *

    Suppose headers are represented by {@code Map>}. A + * supplier and a consumer of {@link ByteBuffer}s in forms of {@code + * Supplier} and {@code Consumer} respectively. Then to + * encode headers, the following approach might be used: + * + *

    {@code
    + *     for (Map.Entry> h : headers.entrySet()) {
    + *         String name = h.getKey();
    + *         for (String value : h.getValue()) {
    + *             encoder.header(name, value);        // Set up header
    + *             boolean encoded;
    + *             do {
    + *                 ByteBuffer b = buffersSupplier.get();
    + *                 encoded = encoder.encode(b);    // Encode the header
    + *                 buffersConsumer.accept(b);
    + *             } while (!encoded);
    + *         }
    + *     }
    + * }
    + * + *

    Though the specification does not define how + * an encoder is to be implemented, a default implementation is provided by the + * method {@link #header(CharSequence, CharSequence, boolean)}. + * + *

    To provide a custom encoding implementation, {@code Encoder} has to be + * extended. A subclass then can access methods for encoding using specific + * representations (e.g. {@link #literal(int, CharSequence, boolean) literal}, + * {@link #indexed(int) indexed}, etc.) + * + * @apiNote + * + *

    An Encoder provides an incremental way of encoding headers. + * {@link #encode(ByteBuffer)} takes a buffer a returns a boolean indicating + * whether, or not, the buffer was sufficiently sized to hold the + * remaining of the encoded representation. + * + *

    This way, there's no need to provide a buffer of a specific size, or to + * resize (and copy) the buffer on demand, when the remaining encoded + * representation will not fit in the buffer's remaining space. Instead, an + * array of existing buffers can be used, prepended with a frame that encloses + * the resulting header block afterwards. + * + *

    Splitting the encoding operation into header set up and header encoding, + * separates long lived arguments ({@code name}, {@code value}, {@code + * sensitivity}, etc.) from the short lived ones (e.g. {@code buffer}), + * simplifying each operation itself. + * + * @implNote + * + *

    The default implementation does not use dynamic table. It reports to a + * coupled Decoder a size update with the value of {@code 0}, and never changes + * it afterwards. + * + * @since 9 + */ +public class Encoder { + + // TODO: enum: no huffman/smart huffman/always huffman + private static final boolean DEFAULT_HUFFMAN = true; + + private final IndexedWriter indexedWriter = new IndexedWriter(); + private final LiteralWriter literalWriter = new LiteralWriter(); + private final LiteralNeverIndexedWriter literalNeverIndexedWriter + = new LiteralNeverIndexedWriter(); + private final LiteralWithIndexingWriter literalWithIndexingWriter + = new LiteralWithIndexingWriter(); + private final SizeUpdateWriter sizeUpdateWriter = new SizeUpdateWriter(); + private final BulkSizeUpdateWriter bulkSizeUpdateWriter + = new BulkSizeUpdateWriter(); + + private BinaryRepresentationWriter writer; + private final HeaderTable headerTable; + + private boolean encoding; + + private int maxCapacity; + private int currCapacity; + private int lastCapacity; + private long minCapacity; + private boolean capacityUpdate; + private boolean configuredCapacityUpdate; + + /** + * Constructs an {@code Encoder} with the specified maximum capacity of the + * header table. + * + *

    The value has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK (see 4.2. Maximum Table + * Size). + * + * @param maxCapacity + * a non-negative integer + * + * @throws IllegalArgumentException + * if maxCapacity is negative + */ + public Encoder(int maxCapacity) { + if (maxCapacity < 0) { + throw new IllegalArgumentException("maxCapacity >= 0: " + maxCapacity); + } + // Initial maximum capacity update mechanics + minCapacity = Long.MAX_VALUE; + currCapacity = -1; + setMaxCapacity(maxCapacity); + headerTable = new HeaderTable(lastCapacity); + } + + /** + * Sets up the given header {@code (name, value)}. + * + *

    Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, CharSequence value) + throws IllegalStateException { + header(name, value, false); + } + + /** + * Sets up the given header {@code (name, value)} with possibly sensitive + * value. + * + *

    Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * @param sensitive + * whether or not the value is sensitive + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence) + * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, CharSequence value, + boolean sensitive) throws IllegalStateException { + // Arguably a good balance between complexity of implementation and + // efficiency of encoding + requireNonNull(name, "name"); + requireNonNull(value, "value"); + HeaderTable t = getHeaderTable(); + int index = t.indexOf(name, value); + if (index > 0) { + indexed(index); + } else if (index < 0) { + if (sensitive) { + literalNeverIndexed(-index, value, DEFAULT_HUFFMAN); + } else { + literal(-index, value, DEFAULT_HUFFMAN); + } + } else { + if (sensitive) { + literalNeverIndexed(name, DEFAULT_HUFFMAN, value, DEFAULT_HUFFMAN); + } else { + literal(name, DEFAULT_HUFFMAN, value, DEFAULT_HUFFMAN); + } + } + } + + /** + * Sets a maximum capacity of the header table. + * + *

    The value has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK (see 4.2. Maximum Table + * Size). + * + *

    May be called any number of times after or before a complete header + * has been encoded. + * + *

    If the encoder decides to change the actual capacity, an update will + * be encoded before a new encoding operation starts. + * + * @param capacity + * a non-negative integer + * + * @throws IllegalArgumentException + * if capacity is negative + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + */ + public void setMaxCapacity(int capacity) { + checkEncoding(); + if (capacity < 0) { + throw new IllegalArgumentException("capacity >= 0: " + capacity); + } + int calculated = calculateCapacity(capacity); + if (calculated < 0 || calculated > capacity) { + throw new IllegalArgumentException( + format("0 <= calculated <= capacity: calculated=%s, capacity=%s", + calculated, capacity)); + } + capacityUpdate = true; + // maxCapacity needs to be updated unconditionally, so the encoder + // always has the newest one (in case it decides to update it later + // unsolicitedly) + // Suppose maxCapacity = 4096, and the encoder has decided to use only + // 2048. It later can choose anything else from the region [0, 4096]. + maxCapacity = capacity; + lastCapacity = calculated; + minCapacity = Math.min(minCapacity, lastCapacity); + } + + protected int calculateCapacity(int maxCapacity) { + // Default implementation of the Encoder won't add anything to the + // table, therefore no need for a table space + return 0; + } + + /** + * Encodes the {@linkplain #header(CharSequence, CharSequence) set up} + * header into the given buffer. + * + *

    The encoder writes as much as possible of the header's binary + * representation into the given buffer, starting at the buffer's position, + * and increments its position to reflect the bytes written. The buffer's + * mark and limit will not be modified. + * + *

    Once the method has returned {@code true}, the current header is + * deemed encoded. A new header may be set up. + * + * @param headerBlock + * the buffer to encode the header into, may be empty + * + * @return {@code true} if the current header has been fully encoded, + * {@code false} otherwise + * + * @throws NullPointerException + * if the buffer is {@code null} + * @throws ReadOnlyBufferException + * if this buffer is read-only + * @throws IllegalStateException + * if there is no set up header + */ + public final boolean encode(ByteBuffer headerBlock) { + if (!encoding) { + throw new IllegalStateException("A header hasn't been set up"); + } + if (!prependWithCapacityUpdate(headerBlock)) { + return false; + } + boolean done = writer.write(headerTable, headerBlock); + if (done) { + writer.reset(); // FIXME: WHY? + encoding = false; + } + return done; + } + + private boolean prependWithCapacityUpdate(ByteBuffer headerBlock) { + if (capacityUpdate) { + if (!configuredCapacityUpdate) { + List sizes = new LinkedList<>(); + if (minCapacity < currCapacity) { + sizes.add((int) minCapacity); + if (minCapacity != lastCapacity) { + sizes.add(lastCapacity); + } + } else if (lastCapacity != currCapacity) { + sizes.add(lastCapacity); + } + bulkSizeUpdateWriter.maxHeaderTableSizes(sizes); + configuredCapacityUpdate = true; + } + boolean done = bulkSizeUpdateWriter.write(headerTable, headerBlock); + if (done) { + minCapacity = lastCapacity; + currCapacity = lastCapacity; + bulkSizeUpdateWriter.reset(); + capacityUpdate = false; + configuredCapacityUpdate = false; + } + return done; + } + return true; + } + + protected final void indexed(int index) throws IndexOutOfBoundsException { + checkEncoding(); + encoding = true; + writer = indexedWriter.index(index); + } + + protected final void literal(int index, CharSequence value, + boolean useHuffman) + throws IndexOutOfBoundsException { + checkEncoding(); + encoding = true; + writer = literalWriter + .index(index).value(value, useHuffman); + } + + protected final void literal(CharSequence name, boolean nameHuffman, + CharSequence value, boolean valueHuffman) { + checkEncoding(); + encoding = true; + writer = literalWriter + .name(name, nameHuffman).value(value, valueHuffman); + } + + protected final void literalNeverIndexed(int index, + CharSequence value, + boolean valueHuffman) + throws IndexOutOfBoundsException { + checkEncoding(); + encoding = true; + writer = literalNeverIndexedWriter + .index(index).value(value, valueHuffman); + } + + protected final void literalNeverIndexed(CharSequence name, + boolean nameHuffman, + CharSequence value, + boolean valueHuffman) { + checkEncoding(); + encoding = true; + writer = literalNeverIndexedWriter + .name(name, nameHuffman).value(value, valueHuffman); + } + + protected final void literalWithIndexing(int index, + CharSequence value, + boolean valueHuffman) + throws IndexOutOfBoundsException { + checkEncoding(); + encoding = true; + writer = literalWithIndexingWriter + .index(index).value(value, valueHuffman); + } + + protected final void literalWithIndexing(CharSequence name, + boolean nameHuffman, + CharSequence value, + boolean valueHuffman) { + checkEncoding(); + encoding = true; + writer = literalWithIndexingWriter + .name(name, nameHuffman).value(value, valueHuffman); + } + + protected final void sizeUpdate(int capacity) + throws IllegalArgumentException { + checkEncoding(); + // Ensure subclass follows the contract + if (capacity > this.maxCapacity) { + throw new IllegalArgumentException( + format("capacity <= maxCapacity: capacity=%s, maxCapacity=%s", + capacity, maxCapacity)); + } + writer = sizeUpdateWriter.maxHeaderTableSize(capacity); + } + + protected final int getMaxCapacity() { + return maxCapacity; + } + + protected final HeaderTable getHeaderTable() { + return headerTable; + } + + protected final void checkEncoding() { + if (encoding) { + throw new IllegalStateException( + "Previous encoding operation hasn't finished yet"); + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java new file mode 100644 index 00000000000..89820741a32 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.NoSuchElementException; + +import static java.lang.String.format; + +// +// Header Table combined from two tables: static and dynamic. +// +// There is a single address space for index values. Index-aware methods +// correspond to the table as a whole. Size-aware methods only to the dynamic +// part of it. +// +final class HeaderTable { + + private static final HeaderField[] staticTable = { + null, // To make index 1-based, instead of 0-based + new HeaderField(":authority"), + new HeaderField(":method", "GET"), + new HeaderField(":method", "POST"), + new HeaderField(":path", "/"), + new HeaderField(":path", "/index.html"), + new HeaderField(":scheme", "http"), + new HeaderField(":scheme", "https"), + new HeaderField(":status", "200"), + new HeaderField(":status", "204"), + new HeaderField(":status", "206"), + new HeaderField(":status", "304"), + new HeaderField(":status", "400"), + new HeaderField(":status", "404"), + new HeaderField(":status", "500"), + new HeaderField("accept-charset"), + new HeaderField("accept-encoding", "gzip, deflate"), + new HeaderField("accept-language"), + new HeaderField("accept-ranges"), + new HeaderField("accept"), + new HeaderField("access-control-allow-origin"), + new HeaderField("age"), + new HeaderField("allow"), + new HeaderField("authorization"), + new HeaderField("cache-control"), + new HeaderField("content-disposition"), + new HeaderField("content-encoding"), + new HeaderField("content-language"), + new HeaderField("content-length"), + new HeaderField("content-location"), + new HeaderField("content-range"), + new HeaderField("content-type"), + new HeaderField("cookie"), + new HeaderField("date"), + new HeaderField("etag"), + new HeaderField("expect"), + new HeaderField("expires"), + new HeaderField("from"), + new HeaderField("host"), + new HeaderField("if-match"), + new HeaderField("if-modified-since"), + new HeaderField("if-none-match"), + new HeaderField("if-range"), + new HeaderField("if-unmodified-since"), + new HeaderField("last-modified"), + new HeaderField("link"), + new HeaderField("location"), + new HeaderField("max-forwards"), + new HeaderField("proxy-authenticate"), + new HeaderField("proxy-authorization"), + new HeaderField("range"), + new HeaderField("referer"), + new HeaderField("refresh"), + new HeaderField("retry-after"), + new HeaderField("server"), + new HeaderField("set-cookie"), + new HeaderField("strict-transport-security"), + new HeaderField("transfer-encoding"), + new HeaderField("user-agent"), + new HeaderField("vary"), + new HeaderField("via"), + new HeaderField("www-authenticate") + }; + + private static final int STATIC_TABLE_LENGTH = staticTable.length - 1; + private static final int ENTRY_SIZE = 32; + private static final Map> staticIndexes; + + static { + staticIndexes = new HashMap<>(STATIC_TABLE_LENGTH); + for (int i = 1; i <= STATIC_TABLE_LENGTH; i++) { + HeaderField f = staticTable[i]; + Map values = staticIndexes + .computeIfAbsent(f.name, k -> new LinkedHashMap<>()); + values.put(f.value, i); + } + } + + private final Table dynamicTable = new Table(0); + private int maxSize; + private int size; + + public HeaderTable(int maxSize) { + setMaxSize(maxSize); + } + + // + // The method returns: + // + // * a positive integer i where i (i = [1..Integer.MAX_VALUE]) is an + // index of an entry with a header (n, v), where n.equals(name) && + // v.equals(value) + // + // * a negative integer j where j (j = [-Integer.MAX_VALUE..-1]) is an + // index of an entry with a header (n, v), where n.equals(name) + // + // * 0 if there's no entry e such that e.getName().equals(name) + // + // The rationale behind this design is to allow to pack more useful data + // into a single invocation, facilitating a single pass where possible + // (the idea is the same as in java.util.Arrays.binarySearch(int[], int)). + // + public int indexOf(CharSequence name, CharSequence value) { + // Invoking toString() will possibly allocate Strings for the sake of + // the search, which doesn't feel right. + String n = name.toString(); + String v = value.toString(); + + // 1. Try exact match in the static region + Map values = staticIndexes.get(n); + if (values != null) { + Integer idx = values.get(v); + if (idx != null) { + return idx; + } + } + // 2. Try exact match in the dynamic region + int didx = dynamicTable.indexOf(n, v); + if (didx > 0) { + return STATIC_TABLE_LENGTH + didx; + } else if (didx < 0) { + if (values != null) { + // 3. Return name match from the static region + return -values.values().iterator().next(); // Iterator allocation + } else { + // 4. Return name match from the dynamic region + return -STATIC_TABLE_LENGTH + didx; + } + } else { + if (values != null) { + // 3. Return name match from the static region + return -values.values().iterator().next(); // Iterator allocation + } else { + return 0; + } + } + } + + public int size() { + return size; + } + + public int maxSize() { + return maxSize; + } + + public int length() { + return STATIC_TABLE_LENGTH + dynamicTable.size(); + } + + HeaderField get(int index) { + checkIndex(index); + if (index <= STATIC_TABLE_LENGTH) { + return staticTable[index]; + } else { + return dynamicTable.get(index - STATIC_TABLE_LENGTH); + } + } + + void put(CharSequence name, CharSequence value) { + // Invoking toString() will possibly allocate Strings. But that's + // unavoidable at this stage. If a CharSequence is going to be stored in + // the table, it must not be mutable (e.g. for the sake of hashing). + put(new HeaderField(name.toString(), value.toString())); + } + + private void put(HeaderField h) { + int entrySize = sizeOf(h); + while (entrySize > maxSize - size && size != 0) { + evictEntry(); + } + if (entrySize > maxSize - size) { + return; + } + size += entrySize; + dynamicTable.add(h); + } + + void setMaxSize(int maxSize) { + if (maxSize < 0) { + throw new IllegalArgumentException + ("maxSize >= 0: maxSize=" + maxSize); + } + while (maxSize < size && size != 0) { + evictEntry(); + } + this.maxSize = maxSize; + int upperBound = (maxSize / ENTRY_SIZE) + 1; + this.dynamicTable.setCapacity(upperBound); + } + + HeaderField evictEntry() { + HeaderField f = dynamicTable.remove(); + size -= sizeOf(f); + return f; + } + + @Override + public String toString() { + double used = maxSize == 0 ? 0 : 100 * (((double) size) / maxSize); + return format("entries: %d; used %s/%s (%.1f%%)", dynamicTable.size(), + size, maxSize, used); + } + + int checkIndex(int index) { + if (index < 1 || index > STATIC_TABLE_LENGTH + dynamicTable.size()) { + throw new IllegalArgumentException( + format("1 <= index <= length(): index=%s, length()=%s", + index, length())); + } + return index; + } + + int sizeOf(HeaderField f) { + return f.name.length() + f.value.length() + ENTRY_SIZE; + } + + // + // Diagnostic information in the form used in the RFC 7541 + // + String getStateString() { + if (size == 0) { + return "empty."; + } + + StringBuilder b = new StringBuilder(); + for (int i = 1, size = dynamicTable.size(); i <= size; i++) { + HeaderField e = dynamicTable.get(i); + b.append(format("[%3d] (s = %3d) %s: %s%n", i, + sizeOf(e), e.name, e.value)); + } + b.append(format(" Table size:%4s", this.size)); + return b.toString(); + } + + // Convert to a Value Object (JDK-8046159)? + static final class HeaderField { + + final String name; + final String value; + + public HeaderField(String name) { + this(name, ""); + } + + public HeaderField(String name, String value) { + this.name = name; + this.value = value; + } + + @Override + public String toString() { + return value.isEmpty() ? name : name + ": " + value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HeaderField that = (HeaderField) o; + return name.equals(that.name) && value.equals(that.value); + } + + @Override + public int hashCode() { + return 31 * (name.hashCode()) + value.hashCode(); + } + } + + // + // In order to be able to find an index of an entry with the given contents + // in the dynamic table an effective inverse mapping is needed. Here's a + // simple idea behind such a mapping. + // + // # The problem: + // + // We have a queue with an O(1) lookup by index: + // + // get: index -> x + // + // What we also want is an O(1) reverse lookup: + // + // indexOf: x -> index + // + // # Solution: + // + // Let's store an inverse mapping as a Map. This have a problem + // that when a new element is added to the queue all indexes in the map + // becomes invalid. Namely, each i becomes shifted by 1 to the right: + // + // i -> i + 1 + // + // And the new element is assigned with an index of 1. This would seem to + // require a pass through the map incrementing all indexes (map values) by + // 1, which is O(n). + // + // The good news is we can do much better then this! + // + // Let's create a single field of type long, called 'counter'. Then each + // time a new element 'x' is added to the queue, a value of this field gets + // incremented. Then the resulting value of the 'counter_x' is then put as a + // value under key 'x' to the map: + // + // map.put(x, counter_x) + // + // It gives us a map that maps an element to a value the counter had at the + // time the element had been added. + // + // In order to retrieve an index of any element 'x' in the queue (at any + // given time) we simply need to subtract the value (the snapshot of the + // counter at the time when the 'x' was added) from the current value of the + // counter. This operation basically answers the question: + // + // How many elements ago 'x' was the tail of the queue? + // + // Which is the same as its index in the queue now. Given, of course, it's + // still in the queue. + // + // I'm pretty sure in a real life long overflow will never happen, so it's + // not too practical to add recalibrating code, but a pedantic person might + // want to do so: + // + // if (counter == Long.MAX_VALUE) { + // recalibrate(); + // } + // + // Where 'recalibrate()' goes through the table doing this: + // + // value -= counter + // + // That's given, of course, the size of the table itself is less than + // Long.MAX_VALUE :-) + // + private static final class Table { + + private final Map> map; + private final CircularBuffer buffer; + private long counter = 1; + + Table(int capacity) { + buffer = new CircularBuffer<>(capacity); + map = new HashMap<>(capacity); + } + + void add(HeaderField f) { + buffer.add(f); + Map values = map.computeIfAbsent(f.name, k -> new HashMap<>()); + values.put(f.value, counter++); + } + + HeaderField get(int index) { + return buffer.get(index - 1); + } + + int indexOf(String name, String value) { + Map values = map.get(name); + if (values == null) { + return 0; + } + Long index = values.get(value); + if (index != null) { + return (int) (counter - index); + } else { + assert !values.isEmpty(); + Long any = values.values().iterator().next(); // Iterator allocation + return -(int) (counter - any); + } + } + + HeaderField remove() { + HeaderField f = buffer.remove(); + Map values = map.get(f.name); + Long index = values.remove(f.value); + assert index != null; + if (values.isEmpty()) { + map.remove(f.name); + } + return f; + } + + int size() { + return buffer.size; + } + + public void setCapacity(int capacity) { + buffer.resize(capacity); + } + } + + // head + // v + // [ ][ ][A][B][C][D][ ][ ][ ] + // ^ + // tail + // + // |<- size ->| (4) + // |<------ capacity ------->| (9) + // + static final class CircularBuffer { + + int tail, head, size, capacity; + Object[] elements; + + CircularBuffer(int capacity) { + this.capacity = capacity; + elements = new Object[capacity]; + } + + void add(E elem) { + if (size == capacity) { + throw new IllegalStateException( + format("No room for '%s': capacity=%s", elem, capacity)); + } + elements[head] = elem; + head = (head + 1) % capacity; + size++; + } + + @SuppressWarnings("unchecked") + E remove() { + if (size == 0) { + throw new NoSuchElementException("Empty"); + } + E elem = (E) elements[tail]; + elements[tail] = null; + tail = (tail + 1) % capacity; + size--; + return elem; + } + + @SuppressWarnings("unchecked") + E get(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException( + format("0 <= index <= capacity: index=%s, capacity=%s", + index, capacity)); + } + int idx = (tail + (size - index - 1)) % capacity; + return (E) elements[idx]; + } + + public void resize(int newCapacity) { + if (newCapacity < size) { + throw new IllegalStateException( + format("newCapacity >= size: newCapacity=%s, size=%s", + newCapacity, size)); + } + + Object[] newElements = new Object[newCapacity]; + + if (tail < head || size == 0) { + System.arraycopy(elements, tail, newElements, 0, size); + } else { + System.arraycopy(elements, tail, newElements, 0, elements.length - tail); + System.arraycopy(elements, 0, newElements, elements.length - tail, head); + } + + elements = newElements; + tail = 0; + head = size; + this.capacity = newCapacity; + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Huffman.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Huffman.java new file mode 100644 index 00000000000..9c58cc3acc2 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Huffman.java @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; + +import static java.lang.String.format; + +/** + * Huffman coding table. + * + *

    Instances of this class are safe for use by multiple threads. + * + * @since 9 + */ +public final class Huffman { + + // TODO: check if reset is done in both reader and writer + + static final class Reader { + + private Node curr; // position in the trie + private int len; // length of the path from the root to 'curr' + private int p; // byte probe + + { + reset(); + } + + public void read(ByteBuffer source, Appendable destination, + boolean isLast) { + read(source, destination, true, isLast); + } + + // Takes 'isLast' rather than returns whether the reading is done or + // not, for more informative exceptions. + void read(ByteBuffer source, Appendable destination, boolean reportEOS, + boolean isLast) { + + Node c = curr; + int l = len; + /* + Since ByteBuffer is itself stateful, its position is + remembered here NOT as a part of Reader's state, + but to set it back in the case of a failure + */ + int pos = source.position(); + + while (source.hasRemaining()) { + int d = source.get(); + for (; p != 0; p >>= 1) { + c = c.getChild(p & d); + l++; + if (c.isLeaf()) { + if (reportEOS && c.isEOSPath) { + throw new IllegalArgumentException("Encountered EOS"); + } + try { + destination.append(c.getChar()); + } catch (RuntimeException | Error e) { + source.position(pos); + throw e; + } catch (IOException e) { + source.position(pos); + throw new UncheckedIOException(e); + } + c = INSTANCE.root; + l = 0; + } + curr = c; + len = l; + } + resetProbe(); + pos++; + } + if (!isLast) { + return; // it's too early to jump to any conclusions, let's wait + } + if (c.isLeaf()) { + return; // it's perfectly ok, no extra padding bits + } + if (c.isEOSPath && len <= 7) { + return; // it's ok, some extra padding bits + } + if (c.isEOSPath) { + throw new IllegalArgumentException( + "Padding is too long (len=" + len + ") " + + "or unexpected end of data"); + } + throw new IllegalArgumentException( + "Not a EOS prefix padding or unexpected end of data"); + } + + public void reset() { + curr = INSTANCE.root; + len = 0; + resetProbe(); + } + + private void resetProbe() { + p = 0x80; + } + } + + static final class Writer { + + private int pos; // position in 'source' + private int avail = 8; // number of least significant bits available in 'curr' + private int curr; // next byte to put to the destination + private int rem; // number of least significant bits in 'code' yet to be processed + private int code; // current code being written + + private CharSequence source; + private int end; + + public Writer from(CharSequence input, int start, int end) { + if (start < 0 || end < 0 || end > input.length() || start > end) { + throw new IndexOutOfBoundsException( + String.format("input.length()=%s, start=%s, end=%s", + input.length(), start, end)); + } + pos = start; + this.end = end; + this.source = input; + return this; + } + + public boolean write(ByteBuffer destination) { + for (; pos < end; pos++) { + if (rem == 0) { + Code desc = INSTANCE.codeOf(source.charAt(pos)); + rem = desc.length; + code = desc.code; + } + while (rem > 0) { + if (rem < avail) { + curr |= (code << (avail - rem)); + avail -= rem; + rem = 0; + } else { + int c = (curr | (code >>> (rem - avail))); + if (destination.hasRemaining()) { + destination.put((byte) c); + } else { + return false; + } + curr = c; + code <<= (32 - rem + avail); // throw written bits off the cliff (is this Sparta?) + code >>>= (32 - rem + avail); // return to the position + rem -= avail; + curr = 0; + avail = 8; + } + } + } + + if (avail < 8) { // have to pad + if (destination.hasRemaining()) { + destination.put((byte) (curr | (INSTANCE.EOS.code >>> (INSTANCE.EOS.length - avail)))); + avail = 8; + } else { + return false; + } + } + + return true; + } + + public Writer reset() { + source = null; + end = -1; + pos = -1; + avail = 8; + curr = 0; + code = 0; + return this; + } + } + + /** + * Shared instance. + */ + public static final Huffman INSTANCE = new Huffman(); + + private final Code EOS = new Code(0x3fffffff, 30); + private final Code[] codes = new Code[257]; + private final Node root = new Node() { + @Override + public String toString() { return "root"; } + }; + + // TODO: consider builder and immutable trie + private Huffman() { + // @formatter:off + addChar(0, 0x1ff8, 13); + addChar(1, 0x7fffd8, 23); + addChar(2, 0xfffffe2, 28); + addChar(3, 0xfffffe3, 28); + addChar(4, 0xfffffe4, 28); + addChar(5, 0xfffffe5, 28); + addChar(6, 0xfffffe6, 28); + addChar(7, 0xfffffe7, 28); + addChar(8, 0xfffffe8, 28); + addChar(9, 0xffffea, 24); + addChar(10, 0x3ffffffc, 30); + addChar(11, 0xfffffe9, 28); + addChar(12, 0xfffffea, 28); + addChar(13, 0x3ffffffd, 30); + addChar(14, 0xfffffeb, 28); + addChar(15, 0xfffffec, 28); + addChar(16, 0xfffffed, 28); + addChar(17, 0xfffffee, 28); + addChar(18, 0xfffffef, 28); + addChar(19, 0xffffff0, 28); + addChar(20, 0xffffff1, 28); + addChar(21, 0xffffff2, 28); + addChar(22, 0x3ffffffe, 30); + addChar(23, 0xffffff3, 28); + addChar(24, 0xffffff4, 28); + addChar(25, 0xffffff5, 28); + addChar(26, 0xffffff6, 28); + addChar(27, 0xffffff7, 28); + addChar(28, 0xffffff8, 28); + addChar(29, 0xffffff9, 28); + addChar(30, 0xffffffa, 28); + addChar(31, 0xffffffb, 28); + addChar(32, 0x14, 6); + addChar(33, 0x3f8, 10); + addChar(34, 0x3f9, 10); + addChar(35, 0xffa, 12); + addChar(36, 0x1ff9, 13); + addChar(37, 0x15, 6); + addChar(38, 0xf8, 8); + addChar(39, 0x7fa, 11); + addChar(40, 0x3fa, 10); + addChar(41, 0x3fb, 10); + addChar(42, 0xf9, 8); + addChar(43, 0x7fb, 11); + addChar(44, 0xfa, 8); + addChar(45, 0x16, 6); + addChar(46, 0x17, 6); + addChar(47, 0x18, 6); + addChar(48, 0x0, 5); + addChar(49, 0x1, 5); + addChar(50, 0x2, 5); + addChar(51, 0x19, 6); + addChar(52, 0x1a, 6); + addChar(53, 0x1b, 6); + addChar(54, 0x1c, 6); + addChar(55, 0x1d, 6); + addChar(56, 0x1e, 6); + addChar(57, 0x1f, 6); + addChar(58, 0x5c, 7); + addChar(59, 0xfb, 8); + addChar(60, 0x7ffc, 15); + addChar(61, 0x20, 6); + addChar(62, 0xffb, 12); + addChar(63, 0x3fc, 10); + addChar(64, 0x1ffa, 13); + addChar(65, 0x21, 6); + addChar(66, 0x5d, 7); + addChar(67, 0x5e, 7); + addChar(68, 0x5f, 7); + addChar(69, 0x60, 7); + addChar(70, 0x61, 7); + addChar(71, 0x62, 7); + addChar(72, 0x63, 7); + addChar(73, 0x64, 7); + addChar(74, 0x65, 7); + addChar(75, 0x66, 7); + addChar(76, 0x67, 7); + addChar(77, 0x68, 7); + addChar(78, 0x69, 7); + addChar(79, 0x6a, 7); + addChar(80, 0x6b, 7); + addChar(81, 0x6c, 7); + addChar(82, 0x6d, 7); + addChar(83, 0x6e, 7); + addChar(84, 0x6f, 7); + addChar(85, 0x70, 7); + addChar(86, 0x71, 7); + addChar(87, 0x72, 7); + addChar(88, 0xfc, 8); + addChar(89, 0x73, 7); + addChar(90, 0xfd, 8); + addChar(91, 0x1ffb, 13); + addChar(92, 0x7fff0, 19); + addChar(93, 0x1ffc, 13); + addChar(94, 0x3ffc, 14); + addChar(95, 0x22, 6); + addChar(96, 0x7ffd, 15); + addChar(97, 0x3, 5); + addChar(98, 0x23, 6); + addChar(99, 0x4, 5); + addChar(100, 0x24, 6); + addChar(101, 0x5, 5); + addChar(102, 0x25, 6); + addChar(103, 0x26, 6); + addChar(104, 0x27, 6); + addChar(105, 0x6, 5); + addChar(106, 0x74, 7); + addChar(107, 0x75, 7); + addChar(108, 0x28, 6); + addChar(109, 0x29, 6); + addChar(110, 0x2a, 6); + addChar(111, 0x7, 5); + addChar(112, 0x2b, 6); + addChar(113, 0x76, 7); + addChar(114, 0x2c, 6); + addChar(115, 0x8, 5); + addChar(116, 0x9, 5); + addChar(117, 0x2d, 6); + addChar(118, 0x77, 7); + addChar(119, 0x78, 7); + addChar(120, 0x79, 7); + addChar(121, 0x7a, 7); + addChar(122, 0x7b, 7); + addChar(123, 0x7ffe, 15); + addChar(124, 0x7fc, 11); + addChar(125, 0x3ffd, 14); + addChar(126, 0x1ffd, 13); + addChar(127, 0xffffffc, 28); + addChar(128, 0xfffe6, 20); + addChar(129, 0x3fffd2, 22); + addChar(130, 0xfffe7, 20); + addChar(131, 0xfffe8, 20); + addChar(132, 0x3fffd3, 22); + addChar(133, 0x3fffd4, 22); + addChar(134, 0x3fffd5, 22); + addChar(135, 0x7fffd9, 23); + addChar(136, 0x3fffd6, 22); + addChar(137, 0x7fffda, 23); + addChar(138, 0x7fffdb, 23); + addChar(139, 0x7fffdc, 23); + addChar(140, 0x7fffdd, 23); + addChar(141, 0x7fffde, 23); + addChar(142, 0xffffeb, 24); + addChar(143, 0x7fffdf, 23); + addChar(144, 0xffffec, 24); + addChar(145, 0xffffed, 24); + addChar(146, 0x3fffd7, 22); + addChar(147, 0x7fffe0, 23); + addChar(148, 0xffffee, 24); + addChar(149, 0x7fffe1, 23); + addChar(150, 0x7fffe2, 23); + addChar(151, 0x7fffe3, 23); + addChar(152, 0x7fffe4, 23); + addChar(153, 0x1fffdc, 21); + addChar(154, 0x3fffd8, 22); + addChar(155, 0x7fffe5, 23); + addChar(156, 0x3fffd9, 22); + addChar(157, 0x7fffe6, 23); + addChar(158, 0x7fffe7, 23); + addChar(159, 0xffffef, 24); + addChar(160, 0x3fffda, 22); + addChar(161, 0x1fffdd, 21); + addChar(162, 0xfffe9, 20); + addChar(163, 0x3fffdb, 22); + addChar(164, 0x3fffdc, 22); + addChar(165, 0x7fffe8, 23); + addChar(166, 0x7fffe9, 23); + addChar(167, 0x1fffde, 21); + addChar(168, 0x7fffea, 23); + addChar(169, 0x3fffdd, 22); + addChar(170, 0x3fffde, 22); + addChar(171, 0xfffff0, 24); + addChar(172, 0x1fffdf, 21); + addChar(173, 0x3fffdf, 22); + addChar(174, 0x7fffeb, 23); + addChar(175, 0x7fffec, 23); + addChar(176, 0x1fffe0, 21); + addChar(177, 0x1fffe1, 21); + addChar(178, 0x3fffe0, 22); + addChar(179, 0x1fffe2, 21); + addChar(180, 0x7fffed, 23); + addChar(181, 0x3fffe1, 22); + addChar(182, 0x7fffee, 23); + addChar(183, 0x7fffef, 23); + addChar(184, 0xfffea, 20); + addChar(185, 0x3fffe2, 22); + addChar(186, 0x3fffe3, 22); + addChar(187, 0x3fffe4, 22); + addChar(188, 0x7ffff0, 23); + addChar(189, 0x3fffe5, 22); + addChar(190, 0x3fffe6, 22); + addChar(191, 0x7ffff1, 23); + addChar(192, 0x3ffffe0, 26); + addChar(193, 0x3ffffe1, 26); + addChar(194, 0xfffeb, 20); + addChar(195, 0x7fff1, 19); + addChar(196, 0x3fffe7, 22); + addChar(197, 0x7ffff2, 23); + addChar(198, 0x3fffe8, 22); + addChar(199, 0x1ffffec, 25); + addChar(200, 0x3ffffe2, 26); + addChar(201, 0x3ffffe3, 26); + addChar(202, 0x3ffffe4, 26); + addChar(203, 0x7ffffde, 27); + addChar(204, 0x7ffffdf, 27); + addChar(205, 0x3ffffe5, 26); + addChar(206, 0xfffff1, 24); + addChar(207, 0x1ffffed, 25); + addChar(208, 0x7fff2, 19); + addChar(209, 0x1fffe3, 21); + addChar(210, 0x3ffffe6, 26); + addChar(211, 0x7ffffe0, 27); + addChar(212, 0x7ffffe1, 27); + addChar(213, 0x3ffffe7, 26); + addChar(214, 0x7ffffe2, 27); + addChar(215, 0xfffff2, 24); + addChar(216, 0x1fffe4, 21); + addChar(217, 0x1fffe5, 21); + addChar(218, 0x3ffffe8, 26); + addChar(219, 0x3ffffe9, 26); + addChar(220, 0xffffffd, 28); + addChar(221, 0x7ffffe3, 27); + addChar(222, 0x7ffffe4, 27); + addChar(223, 0x7ffffe5, 27); + addChar(224, 0xfffec, 20); + addChar(225, 0xfffff3, 24); + addChar(226, 0xfffed, 20); + addChar(227, 0x1fffe6, 21); + addChar(228, 0x3fffe9, 22); + addChar(229, 0x1fffe7, 21); + addChar(230, 0x1fffe8, 21); + addChar(231, 0x7ffff3, 23); + addChar(232, 0x3fffea, 22); + addChar(233, 0x3fffeb, 22); + addChar(234, 0x1ffffee, 25); + addChar(235, 0x1ffffef, 25); + addChar(236, 0xfffff4, 24); + addChar(237, 0xfffff5, 24); + addChar(238, 0x3ffffea, 26); + addChar(239, 0x7ffff4, 23); + addChar(240, 0x3ffffeb, 26); + addChar(241, 0x7ffffe6, 27); + addChar(242, 0x3ffffec, 26); + addChar(243, 0x3ffffed, 26); + addChar(244, 0x7ffffe7, 27); + addChar(245, 0x7ffffe8, 27); + addChar(246, 0x7ffffe9, 27); + addChar(247, 0x7ffffea, 27); + addChar(248, 0x7ffffeb, 27); + addChar(249, 0xffffffe, 28); + addChar(250, 0x7ffffec, 27); + addChar(251, 0x7ffffed, 27); + addChar(252, 0x7ffffee, 27); + addChar(253, 0x7ffffef, 27); + addChar(254, 0x7fffff0, 27); + addChar(255, 0x3ffffee, 26); + addEOS (256, EOS.code, EOS.length); + // @formatter:on + } + + + /** + * Calculates the number of bytes required to represent the given {@code + * CharSequence} with the Huffman coding. + * + * @param value + * characters + * + * @return number of bytes + * + * @throws NullPointerException + * if the value is null + */ + public int lengthOf(CharSequence value) { + return lengthOf(value, 0, value.length()); + } + + /** + * Calculates the number of bytes required to represent a subsequence of the + * given {@code CharSequence} with the Huffman coding. + * + * @param value + * characters + * @param start + * the start index, inclusive + * @param end + * the end index, exclusive + * + * @return number of bytes + * + * @throws NullPointerException + * if the value is null + * @throws IndexOutOfBoundsException + * if any invocation of {@code value.charAt(i)}, where {@code start + * <= i < end} would throw an IndexOutOfBoundsException + */ + public int lengthOf(CharSequence value, int start, int end) { + int len = 0; + for (int i = start; i < end; i++) { + char c = value.charAt(i); + len += INSTANCE.codeOf(c).length; + } + // Integer division with ceiling, assumption: + assert (len / 8 + (len % 8 != 0 ? 1 : 0)) == (len + 7) / 8 : len; + return (len + 7) / 8; + } + + private void addChar(int c, int code, int bitLength) { + addLeaf(c, code, bitLength, false); + codes[c] = new Code(code, bitLength); + } + + private void addEOS(int c, int code, int bitLength) { + addLeaf(c, code, bitLength, true); + codes[c] = new Code(code, bitLength); + } + + private void addLeaf(int c, int code, int bitLength, boolean isEOS) { + if (bitLength < 1) { + throw new IllegalArgumentException("bitLength < 1"); + } + Node curr = root; + for (int p = 1 << bitLength - 1; p != 0 && !curr.isLeaf(); p = p >> 1) { + curr.isEOSPath |= isEOS; // If it's already true, it can't become false + curr = curr.addChildIfAbsent(p & code); + } + curr.isEOSPath |= isEOS; // The last one needs to have this property as well + if (curr.isLeaf()) { + throw new IllegalStateException("Specified code is already taken"); + } + curr.setChar((char) c); + } + + private Code codeOf(char c) { + if (c > 255) { + throw new IllegalArgumentException("char=" + ((int) c)); + } + return codes[c]; + } + + // + // For debugging/testing purposes + // + Node getRoot() { + return root; + } + + // + // Guarantees: + // + // if (isLeaf() == true) => getChar() is a legal call + // if (isLeaf() == false) => getChild(i) is a legal call (though it can + // return null) + // + static class Node { + + Node left; + Node right; + boolean isEOSPath; + + boolean charIsSet; + char c; + + Node getChild(int selector) { + if (isLeaf()) { + throw new IllegalStateException("This is a leaf node"); + } + Node result = selector == 0 ? left : right; + if (result == null) { + throw new IllegalStateException(format( + "Node doesn't have a child (selector=%s)", selector)); + } + return result; + } + + boolean isLeaf() { + return charIsSet; + } + + char getChar() { + if (!isLeaf()) { + throw new IllegalStateException("This node is not a leaf node"); + } + return c; + } + + void setChar(char c) { + if (charIsSet) { + throw new IllegalStateException( + "This node has been taken already"); + } + if (left != null || right != null) { + throw new IllegalStateException("The node cannot be made " + + "a leaf as it's already has a child"); + } + this.c = c; + charIsSet = true; + } + + Node addChildIfAbsent(int i) { + if (charIsSet) { + throw new IllegalStateException("The node cannot have a child " + + "as it's already a leaf node"); + } + Node child; + if (i == 0) { + if ((child = left) == null) { + child = left = new Node(); + } + } else { + if ((child = right) == null) { + child = right = new Node(); + } + } + return child; + } + + @Override + public String toString() { + if (isLeaf()) { + if (isEOSPath) { + return "EOS"; + } else { + return format("char: (%3s) '%s'", (int) c, c); + } + } + return "/\\"; + } + } + + // TODO: value-based class? + // FIXME: can we re-use Node instead of this class? + private static final class Code { + + final int code; + final int length; + + private Code(int code, int length) { + this.code = code; + this.length = length; + } + + public int getCode() { + return code; + } + + public int getLength() { + return length; + } + + @Override + public String toString() { + long p = 1 << length; + return Long.toBinaryString(code + p).substring(1) + + ", length=" + length; + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/ISO_8859_1.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/ISO_8859_1.java new file mode 100644 index 00000000000..162c9839ae9 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/ISO_8859_1.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; + +// +// Custom implementation of ISO/IEC 8859-1:1998 +// +// The rationale behind this is not to deal with CharsetEncoder/CharsetDecoder, +// basically because it would require wrapping every single CharSequence into a +// CharBuffer and then copying it back. +// +// But why not to give a CharBuffer instead of Appendable? Because I can choose +// an Appendable (e.g. StringBuilder) that adjusts its length when needed and +// therefore not to deal with pre-sized CharBuffers or copying. +// +// The encoding is simple and well known: 1 byte <-> 1 char +// +final class ISO_8859_1 { + + private ISO_8859_1() { } + + public static final class Reader { + + public void read(ByteBuffer source, Appendable destination) { + for (int i = 0, len = source.remaining(); i < len; i++) { + char c = (char) (source.get() & 0xff); + try { + destination.append(c); + } catch (IOException e) { + throw new UncheckedIOException + ("Error appending to the destination", e); + } + } + } + + public Reader reset() { + return this; + } + } + + public static final class Writer { + + private CharSequence source; + private int pos; + private int end; + + public Writer configure(CharSequence source, int start, int end) { + this.source = source; + this.pos = start; + this.end = end; + return this; + } + + public boolean write(ByteBuffer destination) { + for (; pos < end; pos++) { + char c = source.charAt(pos); + if (c > '\u00FF') { + throw new IllegalArgumentException( + "Illegal ISO-8859-1 char: " + (int) c); + } + if (destination.hasRemaining()) { + destination.put((byte) c); + } else { + return false; + } + } + return true; + } + + public Writer reset() { + source = null; + pos = -1; + end = -1; + return this; + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexNameValueWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexNameValueWriter.java new file mode 100644 index 00000000000..01b4decca00 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexNameValueWriter.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +abstract class IndexNameValueWriter implements BinaryRepresentationWriter { + + private final int pattern; + private final int prefix; + private final IntegerWriter intWriter = new IntegerWriter(); + private final StringWriter nameWriter = new StringWriter(); + private final StringWriter valueWriter = new StringWriter(); + + protected boolean indexedRepresentation; + + private static final int NEW = 0; + private static final int NAME_PART_WRITTEN = 1; + private static final int VALUE_WRITTEN = 2; + + private int state = NEW; + + protected IndexNameValueWriter(int pattern, int prefix) { + this.pattern = pattern; + this.prefix = prefix; + } + + IndexNameValueWriter index(int index) { + indexedRepresentation = true; + intWriter.configure(index, prefix, pattern); + return this; + } + + IndexNameValueWriter name(CharSequence name, boolean useHuffman) { + indexedRepresentation = false; + intWriter.configure(0, prefix, pattern); + nameWriter.configure(name, useHuffman); + return this; + } + + IndexNameValueWriter value(CharSequence value, boolean useHuffman) { + valueWriter.configure(value, useHuffman); + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + if (state < NAME_PART_WRITTEN) { + if (indexedRepresentation) { + if (!intWriter.write(destination)) { + return false; + } + } else { + if (!intWriter.write(destination) || !nameWriter.write(destination)) { + return false; + } + } + state = NAME_PART_WRITTEN; + } + if (state < VALUE_WRITTEN) { + if (!valueWriter.write(destination)) { + return false; + } + state = VALUE_WRITTEN; + } + return state == VALUE_WRITTEN; + } + + @Override + public IndexNameValueWriter reset() { + intWriter.reset(); + if (!indexedRepresentation) { + nameWriter.reset(); + } + valueWriter.reset(); + state = NEW; + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexedWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexedWriter.java new file mode 100644 index 00000000000..4ccd9d76112 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexedWriter.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +final class IndexedWriter implements BinaryRepresentationWriter { + + private final IntegerWriter intWriter = new IntegerWriter(); + + IndexedWriter() { } + + IndexedWriter index(int index) { + intWriter.configure(index, 7, 0b1000_0000); + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + return intWriter.write(destination); + } + + @Override + public BinaryRepresentationWriter reset() { + intWriter.reset(); + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerReader.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerReader.java new file mode 100644 index 00000000000..0e7abcfd2f5 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerReader.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +import static java.lang.String.format; + +final class IntegerReader { + + private static final int NEW = 0; + private static final int CONFIGURED = 1; + private static final int FIRST_BYTE_READ = 2; + private static final int DONE = 4; + + private int state = NEW; + + private int N; + private int maxValue; + private int value; + private long r; + private long b = 1; + + public IntegerReader configure(int N) { + return configure(N, Integer.MAX_VALUE); + } + + // + // Why is it important to configure 'maxValue' here. After all we can wait + // for the integer to be fully read and then check it. Can't we? + // + // Two reasons. + // + // 1. Value wraps around long won't be unnoticed. + // 2. It can spit out an exception as soon as it becomes clear there's + // an overflow. Therefore, no need to wait for the value to be fully read. + // + public IntegerReader configure(int N, int maxValue) { + if (state != NEW) { + throw new IllegalStateException("Already configured"); + } + checkPrefix(N); + if (maxValue < 0) { + throw new IllegalArgumentException( + "maxValue >= 0: maxValue=" + maxValue); + } + this.maxValue = maxValue; + this.N = N; + state = CONFIGURED; + return this; + } + + public boolean read(ByteBuffer input) { + if (state == NEW) { + throw new IllegalStateException("Configure first"); + } + if (state == DONE) { + return true; + } + if (!input.hasRemaining()) { + return false; + } + if (state == CONFIGURED) { + int max = (2 << (N - 1)) - 1; + int n = input.get() & max; + if (n != max) { + value = n; + state = DONE; + return true; + } else { + r = max; + } + state = FIRST_BYTE_READ; + } + if (state == FIRST_BYTE_READ) { + // variable-length quantity (VLQ) + byte i; + do { + if (!input.hasRemaining()) { + return false; + } + i = input.get(); + long increment = b * (i & 127); + if (r + increment > maxValue) { + throw new IllegalArgumentException(format( + "Integer overflow: maxValue=%,d, value=%,d", + maxValue, r + increment)); + } + r += increment; + b *= 128; + } while ((128 & i) == 128); + + value = (int) r; + state = DONE; + return true; + } + throw new InternalError(Arrays.toString( + new Object[]{state, N, maxValue, value, r, b})); + } + + public int get() throws IllegalStateException { + if (state != DONE) { + throw new IllegalStateException("Has not been fully read yet"); + } + return value; + } + + private static void checkPrefix(int N) { + if (N < 1 || N > 8) { + throw new IllegalArgumentException("1 <= N <= 8: N= " + N); + } + } + + public IntegerReader reset() { + b = 1; + state = NEW; + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerWriter.java new file mode 100644 index 00000000000..7fd1c108ab3 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerWriter.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +final class IntegerWriter { + + private static final int NEW = 0; + private static final int CONFIGURED = 1; + private static final int FIRST_BYTE_WRITTEN = 2; + private static final int DONE = 4; + + private int state = NEW; + + private int payload; + private int N; + private int value; + + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | | | | | | | | | + // +---+---+---+-------------------+ + // |<--------->|<----------------->| + // payload N=5 + // + // payload is the contents of the left-hand side part of the octet; + // it is truncated to fit into 8-N bits, where 1 <= N <= 8; + // + public IntegerWriter configure(int value, int N, int payload) { + if (state != NEW) { + throw new IllegalStateException("Already configured"); + } + if (value < 0) { + throw new IllegalArgumentException("value >= 0: value=" + value); + } + checkPrefix(N); + this.value = value; + this.N = N; + this.payload = payload & 0xFF & (0xFFFFFFFF << N); + state = CONFIGURED; + return this; + } + + public boolean write(ByteBuffer output) { + if (state == NEW) { + throw new IllegalStateException("Configure first"); + } + if (state == DONE) { + return true; + } + + if (!output.hasRemaining()) { + return false; + } + if (state == CONFIGURED) { + int max = (2 << (N - 1)) - 1; + if (value < max) { + output.put((byte) (payload | value)); + state = DONE; + return true; + } + output.put((byte) (payload | max)); + value -= max; + state = FIRST_BYTE_WRITTEN; + } + if (state == FIRST_BYTE_WRITTEN) { + while (value >= 128 && output.hasRemaining()) { + output.put((byte) (value % 128 + 128)); + value /= 128; + } + if (!output.hasRemaining()) { + return false; + } + output.put((byte) value); + state = DONE; + return true; + } + throw new InternalError(Arrays.toString( + new Object[]{state, payload, N, value})); + } + + private static void checkPrefix(int N) { + if (N < 1 || N > 8) { + throw new IllegalArgumentException("1 <= N <= 8: N= " + N); + } + } + + public IntegerWriter reset() { + state = NEW; + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralNeverIndexedWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralNeverIndexedWriter.java new file mode 100644 index 00000000000..92547ca13a9 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralNeverIndexedWriter.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 sun.net.httpclient.hpack; + +final class LiteralNeverIndexedWriter extends IndexNameValueWriter { + + LiteralNeverIndexedWriter() { + super(0b0001_0000, 4); + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWithIndexingWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWithIndexingWriter.java new file mode 100644 index 00000000000..5926bd6820e --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWithIndexingWriter.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +final class LiteralWithIndexingWriter extends IndexNameValueWriter { + + private boolean tableUpdated; + + private CharSequence name; + private CharSequence value; + private int index; + + LiteralWithIndexingWriter() { + super(0b0100_0000, 6); + } + + @Override + LiteralWithIndexingWriter index(int index) { + super.index(index); + this.index = index; + return this; + } + + @Override + LiteralWithIndexingWriter name(CharSequence name, boolean useHuffman) { + super.name(name, useHuffman); + this.name = name; + return this; + } + + @Override + LiteralWithIndexingWriter value(CharSequence value, boolean useHuffman) { + super.value(value, useHuffman); + this.value = value; + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + if (!tableUpdated) { + CharSequence n; + if (indexedRepresentation) { + n = table.get(index).name; + } else { + n = name; + } + table.put(n, value); + tableUpdated = true; + } + return super.write(table, destination); + } + + @Override + public IndexNameValueWriter reset() { + tableUpdated = false; + name = null; + value = null; + index = -1; + return super.reset(); + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWriter.java new file mode 100644 index 00000000000..430dac4a384 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWriter.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 sun.net.httpclient.hpack; + +final class LiteralWriter extends IndexNameValueWriter { + + LiteralWriter() { + super(0b0000_0000, 4); + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/SizeUpdateWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/SizeUpdateWriter.java new file mode 100644 index 00000000000..5148afeeddc --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/SizeUpdateWriter.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +final class SizeUpdateWriter implements BinaryRepresentationWriter { + + private final IntegerWriter intWriter = new IntegerWriter(); + private int maxSize; + private boolean tableUpdated; + + SizeUpdateWriter() { } + + SizeUpdateWriter maxHeaderTableSize(int size) { + intWriter.configure(size, 5, 0b0010_0000); + this.maxSize = size; + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + if (!tableUpdated) { + table.setMaxSize(maxSize); + tableUpdated = true; + } + return intWriter.write(destination); + } + + @Override + public BinaryRepresentationWriter reset() { + intWriter.reset(); + maxSize = -1; + tableUpdated = false; + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringReader.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringReader.java new file mode 100644 index 00000000000..e2bbefb1473 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringReader.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +// +// 0 1 2 3 4 5 6 7 +// +---+---+---+---+---+---+---+---+ +// | H | String Length (7+) | +// +---+---------------------------+ +// | String Data (Length octets) | +// +-------------------------------+ +// +final class StringReader { + + private static final int NEW = 0; + private static final int FIRST_BYTE_READ = 1; + private static final int LENGTH_READ = 2; + private static final int DONE = 4; + + private final IntegerReader intReader = new IntegerReader(); + private final Huffman.Reader huffmanReader = new Huffman.Reader(); + private final ISO_8859_1.Reader plainReader = new ISO_8859_1.Reader(); + + private int state = NEW; + + private boolean huffman; + private int remainingLength; + + boolean read(ByteBuffer input, Appendable output) { + if (state == DONE) { + return true; + } + if (!input.hasRemaining()) { + return false; + } + if (state == NEW) { + int p = input.position(); + huffman = (input.get(p) & 0b10000000) != 0; + state = FIRST_BYTE_READ; + intReader.configure(7); + } + if (state == FIRST_BYTE_READ) { + boolean lengthRead = intReader.read(input); + if (!lengthRead) { + return false; + } + remainingLength = intReader.get(); + state = LENGTH_READ; + } + if (state == LENGTH_READ) { + boolean isLast = input.remaining() >= remainingLength; + int oldLimit = input.limit(); + if (isLast) { + input.limit(input.position() + remainingLength); + } + if (huffman) { + huffmanReader.read(input, output, isLast); + } else { + plainReader.read(input, output); + } + if (isLast) { + input.limit(oldLimit); + } + return isLast; + } + throw new InternalError(Arrays.toString( + new Object[]{state, huffman, remainingLength})); + } + + boolean isHuffmanEncoded() { + if (state < FIRST_BYTE_READ) { + throw new IllegalStateException("Has not been fully read yet"); + } + return huffman; + } + + void reset() { + if (huffman) { + huffmanReader.reset(); + } else { + plainReader.reset(); + } + intReader.reset(); + state = NEW; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringWriter.java new file mode 100644 index 00000000000..5c58e371082 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringWriter.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +// +// 0 1 2 3 4 5 6 7 +// +---+---+---+---+---+---+---+---+ +// | H | String Length (7+) | +// +---+---------------------------+ +// | String Data (Length octets) | +// +-------------------------------+ +// +// StringWriter does not require a notion of endOfInput (isLast) in 'write' +// methods due to the nature of string representation in HPACK. Namely, the +// length of the string is put before string's contents. Therefore the length is +// always known beforehand. +// +// Expected use: +// +// configure write* (reset configure write*)* +// +final class StringWriter { + + private static final int NEW = 0; + private static final int CONFIGURED = 1; + private static final int LENGTH_WRITTEN = 2; + private static final int DONE = 4; + + private final IntegerWriter intWriter = new IntegerWriter(); + private final Huffman.Writer huffmanWriter = new Huffman.Writer(); + private final ISO_8859_1.Writer plainWriter = new ISO_8859_1.Writer(); + + private int state = NEW; + private boolean huffman; + + StringWriter configure(CharSequence input, boolean huffman) { + return configure(input, 0, input.length(), huffman); + } + + StringWriter configure(CharSequence input, int start, int end, + boolean huffman) { + if (start < 0 || end < 0 || end > input.length() || start > end) { + throw new IndexOutOfBoundsException( + String.format("input.length()=%s, start=%s, end=%s", + input.length(), start, end)); + } + if (!huffman) { + plainWriter.configure(input, start, end); + intWriter.configure(end - start, 7, 0b0000_0000); + } else { + huffmanWriter.from(input, start, end); + intWriter.configure(Huffman.INSTANCE.lengthOf(input, start, end), + 7, 0b1000_0000); + } + + this.huffman = huffman; + state = CONFIGURED; + return this; + } + + boolean write(ByteBuffer output) { + if (state == DONE) { + return true; + } + if (state == NEW) { + throw new IllegalStateException("Configure first"); + } + if (!output.hasRemaining()) { + return false; + } + if (state == CONFIGURED) { + if (intWriter.write(output)) { + state = LENGTH_WRITTEN; + } else { + return false; + } + } + if (state == LENGTH_WRITTEN) { + boolean written = huffman + ? huffmanWriter.write(output) + : plainWriter.write(output); + if (written) { + state = DONE; + return true; + } else { + return false; + } + } + throw new InternalError(Arrays.toString(new Object[]{state, huffman})); + } + + void reset() { + intWriter.reset(); + if (huffman) { + huffmanWriter.reset(); + } else { + plainWriter.reset(); + } + state = NEW; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/package-info.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/package-info.java new file mode 100644 index 00000000000..5c035ff4662 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/package-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +/** + * HPACK (Header Compression for HTTP/2) implementation conforming to + * RFC 7541. + * + *

    Headers can be decoded and encoded by {@link sun.net.httpclient.hpack.Decoder} + * and {@link sun.net.httpclient.hpack.Encoder} respectively. + * + *

    Instances of these classes are not safe for use by multiple threads. + */ +package sun.net.httpclient.hpack; diff --git a/jdk/test/java/net/httpclient/http2/HpackDriver.java b/jdk/test/java/net/httpclient/http2/HpackDriver.java new file mode 100644 index 00000000000..3bf1bc39a4b --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/HpackDriver.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8153353 + * @modules java.httpclient/sun.net.httpclient.hpack + * @key randomness + * @compile/module=java.httpclient sun/net/httpclient/hpack/SpecHelper.java + * @compile/module=java.httpclient sun/net/httpclient/hpack/TestHelper.java + * @compile/module=java.httpclient sun/net/httpclient/hpack/BuffersTestingKit.java + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.BinaryPrimitivesTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.CircularBufferTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.DecoderTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.EncoderTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.HeaderTableTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.HuffmanTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.TestHelper + */ +public class HpackDriver { } diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BinaryPrimitivesTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BinaryPrimitivesTest.java new file mode 100644 index 00000000000..dedd53329a8 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BinaryPrimitivesTest.java @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; +import static sun.net.httpclient.hpack.BuffersTestingKit.*; +import static sun.net.httpclient.hpack.TestHelper.newRandom; + +// +// Some of the tests below overlap in what they test. This allows to diagnose +// bugs quicker and with less pain by simply ruling out common working bits. +// +public final class BinaryPrimitivesTest { + + private final Random rnd = newRandom(); + + @Test + public void integerRead1() { + verifyRead(bytes(0b00011111, 0b10011010, 0b00001010), 1337, 5); + } + + @Test + public void integerRead2() { + verifyRead(bytes(0b00001010), 10, 5); + } + + @Test + public void integerRead3() { + verifyRead(bytes(0b00101010), 42, 8); + } + + @Test + public void integerWrite1() { + verifyWrite(bytes(0b00011111, 0b10011010, 0b00001010), 1337, 5); + } + + @Test + public void integerWrite2() { + verifyWrite(bytes(0b00001010), 10, 5); + } + + @Test + public void integerWrite3() { + verifyWrite(bytes(0b00101010), 42, 8); + } + + // + // Since readInteger(x) is the inverse of writeInteger(x), thus: + // + // for all x: readInteger(writeInteger(x)) == x + // + @Test + public void integerIdentity() { + final int MAX_VALUE = 1 << 22; + int totalCases = 0; + int maxFilling = 0; + IntegerReader r = new IntegerReader(); + IntegerWriter w = new IntegerWriter(); + ByteBuffer buf = ByteBuffer.allocate(8); + for (int N = 1; N < 9; N++) { + for (int expected = 0; expected <= MAX_VALUE; expected++) { + w.reset().configure(expected, N, 1).write(buf); + buf.flip(); + totalCases++; + maxFilling = Math.max(maxFilling, buf.remaining()); + r.reset().configure(N).read(buf); + assertEquals(r.get(), expected); + buf.clear(); + } + } + System.out.printf("totalCases: %,d, maxFilling: %,d, maxValue: %,d%n", + totalCases, maxFilling, MAX_VALUE); + } + + @Test + public void integerReadChunked() { + final int NUM_TESTS = 1024; + IntegerReader r = new IntegerReader(); + ByteBuffer bb = ByteBuffer.allocate(8); + IntegerWriter w = new IntegerWriter(); + for (int i = 0; i < NUM_TESTS; i++) { + final int N = 1 + rnd.nextInt(8); + final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1; + w.reset().configure(expected, N, rnd.nextInt()).write(bb); + bb.flip(); + + forEachSplit(bb, + (buffers) -> { + Iterable buf = relocateBuffers(injectEmptyBuffers(buffers)); + r.configure(N); + for (ByteBuffer b : buf) { + r.read(b); + } + assertEquals(r.get(), expected); + r.reset(); + }); + bb.clear(); + } + } + + // FIXME: use maxValue in the test + + @Test + // FIXME: tune values for better coverage + public void integerWriteChunked() { + ByteBuffer bb = ByteBuffer.allocate(6); + IntegerWriter w = new IntegerWriter(); + IntegerReader r = new IntegerReader(); + for (int i = 0; i < 1024; i++) { // number of tests + final int N = 1 + rnd.nextInt(8); + final int payload = rnd.nextInt(255); + final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1; + + forEachSplit(bb, + (buffers) -> { + List buf = new ArrayList<>(); + relocateBuffers(injectEmptyBuffers(buffers)).forEach(buf::add); + boolean written = false; + w.configure(expected, N, payload); // TODO: test for payload it can be read after written + for (ByteBuffer b : buf) { + int pos = b.position(); + written = w.write(b); + b.position(pos); + } + if (!written) { + fail("please increase bb size"); + } + r.configure(N).read(concat(buf)); + // TODO: check payload here + assertEquals(r.get(), expected); + w.reset(); + r.reset(); + bb.clear(); + }); + } + } + + + // + // Since readString(x) is the inverse of writeString(x), thus: + // + // for all x: readString(writeString(x)) == x + // + @Test + public void stringIdentity() { + final int MAX_STRING_LENGTH = 4096; + ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); // it takes 6 bytes to encode string length of Integer.MAX_VALUE + CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH); + StringReader reader = new StringReader(); + StringWriter writer = new StringWriter(); + for (int len = 0; len <= MAX_STRING_LENGTH; len++) { + for (int i = 0; i < 64; i++) { + // not so much "test in isolation", I know... we're testing .reset() as well + bytes.clear(); + chars.clear(); + + byte[] b = new byte[len]; + rnd.nextBytes(b); + + String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string + + boolean written = writer + .configure(CharBuffer.wrap(expected), 0, expected.length(), false) + .write(bytes); + + if (!written) { + fail("please increase 'bytes' size"); + } + bytes.flip(); + reader.read(bytes, chars); + chars.flip(); + assertEquals(chars.toString(), expected); + reader.reset(); + writer.reset(); + } + } + } + +// @Test +// public void huffmanStringWriteChunked() { +// fail(); +// } +// +// @Test +// public void huffmanStringReadChunked() { +// fail(); +// } + + @Test + public void stringWriteChunked() { + final int MAX_STRING_LENGTH = 8; + final ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); + final CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH); + final StringReader reader = new StringReader(); + final StringWriter writer = new StringWriter(); + for (int len = 0; len <= MAX_STRING_LENGTH; len++) { + + byte[] b = new byte[len]; + rnd.nextBytes(b); + + String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string + + forEachSplit(bytes, (buffers) -> { + writer.configure(expected, 0, expected.length(), false); + boolean written = false; + for (ByteBuffer buf : buffers) { + int p0 = buf.position(); + written = writer.write(buf); + buf.position(p0); + } + if (!written) { + fail("please increase 'bytes' size"); + } + reader.read(concat(buffers), chars); + chars.flip(); + assertEquals(chars.toString(), expected); + reader.reset(); + writer.reset(); + chars.clear(); + bytes.clear(); + }); + } + } + + @Test + public void stringReadChunked() { + final int MAX_STRING_LENGTH = 16; + final ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); + final CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH); + final StringReader reader = new StringReader(); + final StringWriter writer = new StringWriter(); + for (int len = 0; len <= MAX_STRING_LENGTH; len++) { + + byte[] b = new byte[len]; + rnd.nextBytes(b); + + String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string + + boolean written = writer + .configure(CharBuffer.wrap(expected), 0, expected.length(), false) + .write(bytes); + writer.reset(); + + if (!written) { + fail("please increase 'bytes' size"); + } + bytes.flip(); + + forEachSplit(bytes, (buffers) -> { + for (ByteBuffer buf : buffers) { + int p0 = buf.position(); + reader.read(buf, chars); + buf.position(p0); + } + chars.flip(); + assertEquals(chars.toString(), expected); + reader.reset(); + chars.clear(); + }); + + bytes.clear(); + } + } + +// @Test +// public void test_Huffman_String_Identity() { +// StringWriter writer = new StringWriter(); +// StringReader reader = new StringReader(); +// // 256 * 8 gives 2048 bits in case of plain 8 bit coding +// // 256 * 30 gives you 7680 bits or 960 bytes in case of almost +// // improbable event of 256 30 bits symbols in a row +// ByteBuffer binary = ByteBuffer.allocate(960); +// CharBuffer text = CharBuffer.allocate(960 / 5); // 5 = minimum code length +// for (int len = 0; len < 128; len++) { +// for (int i = 0; i < 256; i++) { +// // not so much "test in isolation", I know... +// binary.clear(); +// +// byte[] bytes = new byte[len]; +// rnd.nextBytes(bytes); +// +// String s = new String(bytes, StandardCharsets.ISO_8859_1); +// +// writer.write(CharBuffer.wrap(s), binary, true); +// binary.flip(); +// reader.read(binary, text); +// text.flip(); +// assertEquals(text.toString(), s); +// } +// } +// } + + // TODO: atomic failures: e.g. readonly/overflow + + private static byte[] bytes(int... data) { + byte[] bytes = new byte[data.length]; + for (int i = 0; i < data.length; i++) { + bytes[i] = (byte) data[i]; + } + return bytes; + } + + private static void verifyRead(byte[] data, int expected, int N) { + ByteBuffer buf = ByteBuffer.wrap(data, 0, data.length); + IntegerReader reader = new IntegerReader(); + reader.configure(N).read(buf); + assertEquals(expected, reader.get()); + } + + private void verifyWrite(byte[] expected, int data, int N) { + IntegerWriter w = new IntegerWriter(); + ByteBuffer buf = ByteBuffer.allocate(2 * expected.length); + w.configure(data, N, 1).write(buf); + buf.flip(); + assertEquals(ByteBuffer.wrap(expected), buf); + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BuffersTestingKit.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BuffersTestingKit.java new file mode 100644 index 00000000000..4f9631647c7 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BuffersTestingKit.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import static java.nio.ByteBuffer.allocate; + +public final class BuffersTestingKit { + + /** + * Relocates a {@code [position, limit)} region of the given buffer to + * corresponding region in a new buffer starting with provided {@code + * newPosition}. + * + *

    Might be useful to make sure ByteBuffer's users do not rely on any + * absolute positions, but solely on what's reported by position(), limit(). + * + *

    The contents between the given buffer and the returned one are not + * shared. + */ + public static ByteBuffer relocate(ByteBuffer buffer, int newPosition, + int newCapacity) { + int oldPosition = buffer.position(); + int oldLimit = buffer.limit(); + + if (newPosition + oldLimit - oldPosition > newCapacity) { + throw new IllegalArgumentException(); + } + + ByteBuffer result; + if (buffer.isDirect()) { + result = ByteBuffer.allocateDirect(newCapacity); + } else { + result = allocate(newCapacity); + } + + result.position(newPosition); + result.put(buffer).limit(result.position()).position(newPosition); + buffer.position(oldPosition); + + if (buffer.isReadOnly()) { + return result.asReadOnlyBuffer(); + } + return result; + } + + public static Iterable relocateBuffers( + Iterable source) { + return () -> + new Iterator() { + + private final Iterator it = source.iterator(); + + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public ByteBuffer next() { + ByteBuffer buf = it.next(); + int remaining = buf.remaining(); + int newCapacity = remaining + random.nextInt(17); + int newPosition = random.nextInt(newCapacity - remaining + 1); + return relocate(buf, newPosition, newCapacity); + } + }; + } + + // TODO: not always of size 0 (it's fine for buffer to report !b.hasRemaining()) + public static Iterable injectEmptyBuffers( + Iterable source) { + return injectEmptyBuffers(source, () -> allocate(0)); + } + + public static Iterable injectEmptyBuffers( + Iterable source, + Supplier emptyBufferFactory) { + + return () -> + new Iterator() { + + private final Iterator it = source.iterator(); + private ByteBuffer next = calculateNext(); + + private ByteBuffer calculateNext() { + if (random.nextBoolean()) { + return emptyBufferFactory.get(); + } else if (it.hasNext()) { + return it.next(); + } else { + return null; + } + } + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public ByteBuffer next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + ByteBuffer next = this.next; + this.next = calculateNext(); + return next; + } + }; + } + + public static ByteBuffer concat(Iterable split) { + return concat(split, ByteBuffer::allocate); + } + + public static ByteBuffer concat(Iterable split, + Function concatBufferFactory) { + int size = 0; + for (ByteBuffer bb : split) { + size += bb.remaining(); + } + + ByteBuffer result = concatBufferFactory.apply(size); + for (ByteBuffer bb : split) { + result.put(bb); + } + + result.flip(); + return result; + } + + public static void forEachSplit(ByteBuffer bb, + Consumer> action) { + forEachSplit(bb.remaining(), + (lengths) -> { + int end = bb.position(); + List buffers = new LinkedList<>(); + for (int len : lengths) { + ByteBuffer d = bb.duplicate(); + d.position(end); + d.limit(end + len); + end += len; + buffers.add(d); + } + action.accept(buffers); + }); + } + + private static void forEachSplit(int n, Consumer> action) { + forEachSplit(n, new Stack<>(), action); + } + + private static void forEachSplit(int n, Stack path, + Consumer> action) { + if (n == 0) { + action.accept(path); + } else { + for (int i = 1; i <= n; i++) { + path.push(i); + forEachSplit(n - i, path, action); + path.pop(); + } + } + } + + private static final Random random = new Random(); + + private BuffersTestingKit() { + throw new InternalError(); + } + +// public static void main(String[] args) { +// +// List buffers = Arrays.asList( +// (ByteBuffer) allocate(3).position(1).limit(2), +// allocate(0), +// allocate(7)); +// +// Iterable buf = relocateBuffers(injectEmptyBuffers(buffers)); +// List result = new ArrayList<>(); +// buf.forEach(result::add); +// System.out.println(result); +// } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/CircularBufferTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/CircularBufferTest.java new file mode 100644 index 00000000000..ebf1cb1d1ee --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/CircularBufferTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import sun.net.httpclient.hpack.HeaderTable.CircularBuffer; + +import java.util.Queue; +import java.util.Random; +import java.util.concurrent.ArrayBlockingQueue; + +import static org.testng.Assert.assertEquals; +import static sun.net.httpclient.hpack.TestHelper.newRandom; + +public final class CircularBufferTest { + + private final Random r = newRandom(); + + @BeforeClass + public void setUp() { + r.setSeed(System.currentTimeMillis()); + } + + @Test + public void queue() { + for (int capacity = 1; capacity <= 2048; capacity++) { + queueOnce(capacity, 32); + } + } + + @Test + public void resize() { + for (int capacity = 1; capacity <= 4096; capacity++) { + resizeOnce(capacity); + } + } + + @Test + public void downSizeEmptyBuffer() { + CircularBuffer buffer = new CircularBuffer<>(16); + buffer.resize(15); + } + + private void resizeOnce(int capacity) { + + int nextNumberToPut = 0; + + Queue referenceQueue = new ArrayBlockingQueue<>(capacity); + CircularBuffer buffer = new CircularBuffer<>(capacity); + + // Fill full, so the next add will wrap + for (int i = 0; i < capacity; i++, nextNumberToPut++) { + buffer.add(nextNumberToPut); + referenceQueue.add(nextNumberToPut); + } + int gets = r.nextInt(capacity); // [0, capacity) + for (int i = 0; i < gets; i++) { + referenceQueue.poll(); + buffer.remove(); + } + int puts = r.nextInt(gets + 1); // [0, gets] + for (int i = 0; i < puts; i++, nextNumberToPut++) { + buffer.add(nextNumberToPut); + referenceQueue.add(nextNumberToPut); + } + + Integer[] expected = referenceQueue.toArray(new Integer[0]); + buffer.resize(expected.length); + + assertEquals(buffer.elements, expected); + } + + private void queueOnce(int capacity, int numWraps) { + + Queue referenceQueue = new ArrayBlockingQueue<>(capacity); + CircularBuffer buffer = new CircularBuffer<>(capacity); + + int nextNumberToPut = 0; + int totalPuts = 0; + int putsLimit = capacity * numWraps; + int remainingCapacity = capacity; + int size = 0; + + while (totalPuts < putsLimit) { + assert remainingCapacity + size == capacity; + int puts = r.nextInt(remainingCapacity + 1); // [0, remainingCapacity] + remainingCapacity -= puts; + size += puts; + for (int i = 0; i < puts; i++, nextNumberToPut++) { + referenceQueue.add(nextNumberToPut); + buffer.add(nextNumberToPut); + } + totalPuts += puts; + int gets = r.nextInt(size + 1); // [0, size] + size -= gets; + remainingCapacity += gets; + for (int i = 0; i < gets; i++) { + Integer expected = referenceQueue.poll(); + Integer actual = buffer.remove(); + assertEquals(actual, expected); + } + } + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/DecoderTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/DecoderTest.java new file mode 100644 index 00000000000..29a651fb0f7 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/DecoderTest.java @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.io.UncheckedIOException; +import java.net.ProtocolException; +import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static sun.net.httpclient.hpack.TestHelper.*; + +public final class DecoderTest { + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.1 + // + @Test + public void example1() { + // @formatter:off + test("400a 6375 7374 6f6d 2d6b 6579 0d63 7573\n" + + "746f 6d2d 6865 6164 6572", + + "[ 1] (s = 55) custom-key: custom-header\n" + + " Table size: 55", + + "custom-key: custom-header"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.2 + // + @Test + public void example2() { + // @formatter:off + test("040c 2f73 616d 706c 652f 7061 7468", + "empty.", + ":path: /sample/path"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.3 + // + @Test + public void example3() { + // @formatter:off + test("1008 7061 7373 776f 7264 0673 6563 7265\n" + + "74", + "empty.", + "password: secret"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.4 + // + @Test + public void example4() { + // @formatter:off + test("82", + "empty.", + ":method: GET"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.3 + // + @Test + public void example5() { + // @formatter:off + Decoder d = new Decoder(256); + + test(d, "8286 8441 0f77 7777 2e65 7861 6d70 6c65\n" + + "2e63 6f6d", + + "[ 1] (s = 57) :authority: www.example.com\n" + + " Table size: 57", + + ":method: GET\n" + + ":scheme: http\n" + + ":path: /\n" + + ":authority: www.example.com"); + + test(d, "8286 84be 5808 6e6f 2d63 6163 6865", + + "[ 1] (s = 53) cache-control: no-cache\n" + + "[ 2] (s = 57) :authority: www.example.com\n" + + " Table size: 110", + + ":method: GET\n" + + ":scheme: http\n" + + ":path: /\n" + + ":authority: www.example.com\n" + + "cache-control: no-cache"); + + test(d, "8287 85bf 400a 6375 7374 6f6d 2d6b 6579\n" + + "0c63 7573 746f 6d2d 7661 6c75 65", + + "[ 1] (s = 54) custom-key: custom-value\n" + + "[ 2] (s = 53) cache-control: no-cache\n" + + "[ 3] (s = 57) :authority: www.example.com\n" + + " Table size: 164", + + ":method: GET\n" + + ":scheme: https\n" + + ":path: /index.html\n" + + ":authority: www.example.com\n" + + "custom-key: custom-value"); + + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.4 + // + @Test + public void example6() { + // @formatter:off + Decoder d = new Decoder(256); + + test(d, "8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4\n" + + "ff", + + "[ 1] (s = 57) :authority: www.example.com\n" + + " Table size: 57", + + ":method: GET\n" + + ":scheme: http\n" + + ":path: /\n" + + ":authority: www.example.com"); + + test(d, "8286 84be 5886 a8eb 1064 9cbf", + + "[ 1] (s = 53) cache-control: no-cache\n" + + "[ 2] (s = 57) :authority: www.example.com\n" + + " Table size: 110", + + ":method: GET\n" + + ":scheme: http\n" + + ":path: /\n" + + ":authority: www.example.com\n" + + "cache-control: no-cache"); + + test(d, "8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925\n" + + "a849 e95b b8e8 b4bf", + + "[ 1] (s = 54) custom-key: custom-value\n" + + "[ 2] (s = 53) cache-control: no-cache\n" + + "[ 3] (s = 57) :authority: www.example.com\n" + + " Table size: 164", + + ":method: GET\n" + + ":scheme: https\n" + + ":path: /index.html\n" + + ":authority: www.example.com\n" + + "custom-key: custom-value"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.5 + // + @Test + public void example7() { + // @formatter:off + Decoder d = new Decoder(256); + + test(d, "4803 3330 3258 0770 7269 7661 7465 611d\n" + + "4d6f 6e2c 2032 3120 4f63 7420 3230 3133\n" + + "2032 303a 3133 3a32 3120 474d 546e 1768\n" + + "7474 7073 3a2f 2f77 7777 2e65 7861 6d70\n" + + "6c65 2e63 6f6d", + + "[ 1] (s = 63) location: https://www.example.com\n" + + "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 3] (s = 52) cache-control: private\n" + + "[ 4] (s = 42) :status: 302\n" + + " Table size: 222", + + ":status: 302\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "location: https://www.example.com"); + + test(d, "4803 3330 37c1 c0bf", + + "[ 1] (s = 42) :status: 307\n" + + "[ 2] (s = 63) location: https://www.example.com\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 4] (s = 52) cache-control: private\n" + + " Table size: 222", + + ":status: 307\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "location: https://www.example.com"); + + test(d, "88c1 611d 4d6f 6e2c 2032 3120 4f63 7420\n" + + "3230 3133 2032 303a 3133 3a32 3220 474d\n" + + "54c0 5a04 677a 6970 7738 666f 6f3d 4153\n" + + "444a 4b48 514b 425a 584f 5157 454f 5049\n" + + "5541 5851 5745 4f49 553b 206d 6178 2d61\n" + + "6765 3d33 3630 303b 2076 6572 7369 6f6e\n" + + "3d31", + + "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + + "[ 2] (s = 52) content-encoding: gzip\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + " Table size: 215", + + ":status: 200\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + "location: https://www.example.com\n" + + "content-encoding: gzip\n" + + "set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.6 + // + @Test + public void example8() { + // @formatter:off + Decoder d = new Decoder(256); + + test(d, "4882 6402 5885 aec3 771a 4b61 96d0 7abe\n" + + "9410 54d4 44a8 2005 9504 0b81 66e0 82a6\n" + + "2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8\n" + + "e9ae 82ae 43d3", + + "[ 1] (s = 63) location: https://www.example.com\n" + + "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 3] (s = 52) cache-control: private\n" + + "[ 4] (s = 42) :status: 302\n" + + " Table size: 222", + + ":status: 302\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "location: https://www.example.com"); + + test(d, "4883 640e ffc1 c0bf", + + "[ 1] (s = 42) :status: 307\n" + + "[ 2] (s = 63) location: https://www.example.com\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 4] (s = 52) cache-control: private\n" + + " Table size: 222", + + ":status: 307\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "location: https://www.example.com"); + + test(d, "88c1 6196 d07a be94 1054 d444 a820 0595\n" + + "040b 8166 e084 a62d 1bff c05a 839b d9ab\n" + + "77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b\n" + + "3960 d5af 2708 7f36 72c1 ab27 0fb5 291f\n" + + "9587 3160 65c0 03ed 4ee5 b106 3d50 07", + + "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + + "[ 2] (s = 52) content-encoding: gzip\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + " Table size: 215", + + ":status: 200\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + "location: https://www.example.com\n" + + "content-encoding: gzip\n" + + "set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"); + // @formatter:on + } + + @Test + // One of responses from Apache Server that helped to catch a bug + public void testX() { + Decoder d = new Decoder(4096); + // @formatter:off + test(d, "3fe1 1f88 6196 d07a be94 03ea 693f 7504\n" + + "00b6 a05c b827 2e32 fa98 b46f 769e 86b1\n" + + "9272 b025 da5c 2ea9 fd70 a8de 7fb5 3556\n" + + "5ab7 6ece c057 02e2 2ad2 17bf 6c96 d07a\n" + + "be94 0854 cb6d 4a08 0075 40bd 71b6 6e05\n" + + "a531 68df 0f13 8efe 4522 cd32 21b6 5686\n" + + "eb23 781f cf52 848f d24a 8f0f 0d02 3435\n" + + "5f87 497c a589 d34d 1f", + + "[ 1] (s = 53) content-type: text/html\n" + + "[ 2] (s = 50) accept-ranges: bytes\n" + + "[ 3] (s = 74) last-modified: Mon, 11 Jun 2007 18:53:14 GMT\n" + + "[ 4] (s = 77) server: Apache/2.4.17 (Unix) OpenSSL/1.0.2e-dev\n" + + "[ 5] (s = 65) date: Mon, 09 Nov 2015 16:26:39 GMT\n" + + " Table size: 319", + + ":status: 200\n" + + "date: Mon, 09 Nov 2015 16:26:39 GMT\n" + + "server: Apache/2.4.17 (Unix) OpenSSL/1.0.2e-dev\n" + + "last-modified: Mon, 11 Jun 2007 18:53:14 GMT\n" + + "etag: \"2d-432a5e4a73a80\"\n" + + "accept-ranges: bytes\n" + + "content-length: 45\n" + + "content-type: text/html"); + // @formatter:on + } + + // + // This test is missing in the spec + // + @Test + public void sizeUpdate() { + Decoder d = new Decoder(4096); + assertEquals(d.getTable().maxSize(), 4096); + d.decode(ByteBuffer.wrap(new byte[]{0b00111110}), true, nopCallback()); // newSize = 30 + assertEquals(d.getTable().maxSize(), 30); + } + + @Test + public void incorrectSizeUpdate() { + ByteBuffer b = ByteBuffer.allocate(8); + Encoder e = new Encoder(8192) { + @Override + protected int calculateCapacity(int maxCapacity) { + return maxCapacity; + } + }; + e.header("a", "b"); + e.encode(b); + b.flip(); + { + Decoder d = new Decoder(4096); + UncheckedIOException ex = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(b, true, (name, value) -> { })); + + assertNotNull(ex.getCause()); + assertEquals(ex.getCause().getClass(), ProtocolException.class); + } + b.flip(); + { + Decoder d = new Decoder(4096); + UncheckedIOException ex = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(b, false, (name, value) -> { })); + + assertNotNull(ex.getCause()); + assertEquals(ex.getCause().getClass(), ProtocolException.class); + } + } + + @Test + public void corruptedHeaderBlockInteger() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + (byte) 0b11111111, // indexed + (byte) 0b10011010 // 25 + ... + }); + UncheckedIOException e = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(data, true, nopCallback())); + assertNotNull(e.getCause()); + assertEquals(e.getCause().getClass(), ProtocolException.class); + assertExceptionMessageContains(e, "Unexpected end of header block"); + } + + // 5.1. Integer Representation + // ... + // Integer encodings that exceed implementation limits -- in value or octet + // length -- MUST be treated as decoding errors. Different limits can + // be set for each of the different uses of integers, based on + // implementation constraints. + @Test + public void headerBlockIntegerNoOverflow() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + (byte) 0b11111111, // indexed + 127 + // Integer.MAX_VALUE - 127 (base 128, little-endian): + (byte) 0b10000000, + (byte) 0b11111111, + (byte) 0b11111111, + (byte) 0b11111111, + (byte) 0b00000111 + }); + + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "index=2147483647"); + } + + @Test + public void headerBlockIntegerOverflow() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + (byte) 0b11111111, // indexed + 127 + // Integer.MAX_VALUE - 127 + 1 (base 128, little endian): + (byte) 0b10000001, + (byte) 0b11111111, + (byte) 0b11111111, + (byte) 0b11111111, + (byte) 0b00000111 + }); + + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "Integer overflow"); + } + + @Test + public void corruptedHeaderBlockString1() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + 0b00001000, // huffman=false, length=8 + 0b00000000, // \ + 0b00000000, // but only 3 octets available... + 0b00000000 // / + }); + UncheckedIOException e = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(data, true, nopCallback())); + assertNotNull(e.getCause()); + assertEquals(e.getCause().getClass(), ProtocolException.class); + assertExceptionMessageContains(e, "Unexpected end of header block"); + } + + @Test + public void corruptedHeaderBlockString2() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10001000, // huffman=true, length=8 + 0b00000000, // \ + 0b00000000, // \ + 0b00000000, // but only 5 octets available... + 0b00000000, // / + 0b00000000 // / + }); + UncheckedIOException e = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(data, true, nopCallback())); + assertNotNull(e.getCause()); + assertEquals(e.getCause().getClass(), ProtocolException.class); + assertExceptionMessageContains(e, "Unexpected end of header block"); + } + + // 5.2. String Literal Representation + // ...A Huffman-encoded string literal containing the EOS symbol MUST be + // treated as a decoding error... + @Test + public void corruptedHeaderBlockHuffmanStringEOS() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10000110, // huffman=true, length=6 + 0b00011001, 0b01001101, (byte) 0b11111111, + (byte) 0b11111111, (byte) 0b11111111, (byte) 0b11111100 + }); + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "Encountered EOS"); + } + + // 5.2. String Literal Representation + // ...A padding strictly longer than 7 bits MUST be treated as a decoding + // error... + @Test + public void corruptedHeaderBlockHuffmanStringLongPadding1() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10000011, // huffman=true, length=3 + 0b00011001, 0b01001101, (byte) 0b11111111 + // len("aei") + len(padding) = (5 + 5 + 5) + (9) + }); + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "Padding is too long", "len=9"); + } + + @Test + public void corruptedHeaderBlockHuffmanStringLongPadding2() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10000011, // huffman=true, length=3 + 0b00011001, 0b01111010, (byte) 0b11111111 + // len("aek") + len(padding) = (5 + 5 + 7) + (7) + }); + assertVoidDoesNotThrow(() -> d.decode(data, true, nopCallback())); + } + + // 5.2. String Literal Representation + // ...A padding not corresponding to the most significant bits of the code + // for the EOS symbol MUST be treated as a decoding error... + @Test + public void corruptedHeaderBlockHuffmanStringNotEOSPadding() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10000011, // huffman=true, length=3 + 0b00011001, 0b01111010, (byte) 0b11111110 + }); + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "Not a EOS prefix"); + } + + @Test + public void argsTestBiConsumerIsNull() { + Decoder decoder = new Decoder(4096); + assertVoidThrows(NullPointerException.class, + () -> decoder.decode(ByteBuffer.allocate(16), true, null)); + } + + @Test + public void argsTestByteBufferIsNull() { + Decoder decoder = new Decoder(4096); + assertVoidThrows(NullPointerException.class, + () -> decoder.decode(null, true, nopCallback())); + } + + @Test + public void argsTestBothAreNull() { + Decoder decoder = new Decoder(4096); + assertVoidThrows(NullPointerException.class, + () -> decoder.decode(null, true, null)); + } + + private static void test(String hexdump, + String headerTable, String headerList) { + test(new Decoder(4096), hexdump, headerTable, headerList); + } + + // + // Sometimes we need to keep the same decoder along several runs, + // as it models the same connection + // + private static void test(Decoder d, String hexdump, + String expectedHeaderTable, String expectedHeaderList) { + + ByteBuffer source = SpecHelper.toBytes(hexdump); + + List actual = new LinkedList<>(); + d.decode(source, true, (name, value) -> { + if (value == null) { + actual.add(name.toString()); + } else { + actual.add(name + ": " + value); + } + }); + + assertEquals(d.getTable().getStateString(), expectedHeaderTable); + assertEquals(actual.stream().collect(Collectors.joining("\n")), expectedHeaderList); + } + + private static DecodingCallback nopCallback() { + return (t, u) -> { }; + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/EncoderTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/EncoderTest.java new file mode 100644 index 00000000000..c7b375b1238 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/EncoderTest.java @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +import static java.util.Arrays.asList; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static sun.net.httpclient.hpack.SpecHelper.toHexdump; +import static sun.net.httpclient.hpack.TestHelper.assertVoidThrows; + +// TODO: map textual representation of commands from the spec to actual +// calls to encoder (actually, this is a good idea for decoder as well) +public final class EncoderTest { + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.1 + // + @Test + public void example1() { + + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + e.literalWithIndexing("custom-key", false, "custom-header", false); + // @formatter:off + test(e, + + "400a 6375 7374 6f6d 2d6b 6579 0d63 7573\n" + + "746f 6d2d 6865 6164 6572", + + "[ 1] (s = 55) custom-key: custom-header\n" + + " Table size: 55"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.2 + // + @Test + public void example2() { + + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + e.literal(4, "/sample/path", false); + // @formatter:off + test(e, + + "040c 2f73 616d 706c 652f 7061 7468", + + "empty."); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.3 + // + @Test + public void example3() { + + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + e.literalNeverIndexed("password", false, "secret", false); + // @formatter:off + test(e, + + "1008 7061 7373 776f 7264 0673 6563 7265\n" + + "74", + + "empty."); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.4 + // + @Test + public void example4() { + + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + e.indexed(2); + // @formatter:off + test(e, + + "82", + + "empty."); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.3 + // + @Test + public void example5() { + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + ByteBuffer output = ByteBuffer.allocate(64); + e.indexed(2); + e.encode(output); + e.indexed(6); + e.encode(output); + e.indexed(4); + e.encode(output); + e.literalWithIndexing(1, "www.example.com", false); + e.encode(output); + + output.flip(); + + // @formatter:off + test(e, output, + + "8286 8441 0f77 7777 2e65 7861 6d70 6c65\n" + + "2e63 6f6d", + + "[ 1] (s = 57) :authority: www.example.com\n" + + " Table size: 57"); + + output.clear(); + + e.indexed( 2); + e.encode(output); + e.indexed( 6); + e.encode(output); + e.indexed( 4); + e.encode(output); + e.indexed(62); + e.encode(output); + e.literalWithIndexing(24, "no-cache", false); + e.encode(output); + + output.flip(); + + test(e, output, + + "8286 84be 5808 6e6f 2d63 6163 6865", + + "[ 1] (s = 53) cache-control: no-cache\n" + + "[ 2] (s = 57) :authority: www.example.com\n" + + " Table size: 110"); + + output.clear(); + + e.indexed( 2); + e.encode(output); + e.indexed( 7); + e.encode(output); + e.indexed( 5); + e.encode(output); + e.indexed(63); + e.encode(output); + e.literalWithIndexing("custom-key", false, "custom-value", false); + e.encode(output); + + output.flip(); + + test(e, output, + + "8287 85bf 400a 6375 7374 6f6d 2d6b 6579\n" + + "0c63 7573 746f 6d2d 7661 6c75 65", + + "[ 1] (s = 54) custom-key: custom-value\n" + + "[ 2] (s = 53) cache-control: no-cache\n" + + "[ 3] (s = 57) :authority: www.example.com\n" + + " Table size: 164"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.4 + // + @Test + public void example6() { + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + ByteBuffer output = ByteBuffer.allocate(64); + e.indexed(2); + e.encode(output); + e.indexed(6); + e.encode(output); + e.indexed(4); + e.encode(output); + e.literalWithIndexing(1, "www.example.com", true); + e.encode(output); + + output.flip(); + + // @formatter:off + test(e, output, + + "8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4\n" + + "ff", + + "[ 1] (s = 57) :authority: www.example.com\n" + + " Table size: 57"); + + output.clear(); + + e.indexed( 2); + e.encode(output); + e.indexed( 6); + e.encode(output); + e.indexed( 4); + e.encode(output); + e.indexed(62); + e.encode(output); + e.literalWithIndexing(24, "no-cache", true); + e.encode(output); + + output.flip(); + + test(e, output, + + "8286 84be 5886 a8eb 1064 9cbf", + + "[ 1] (s = 53) cache-control: no-cache\n" + + "[ 2] (s = 57) :authority: www.example.com\n" + + " Table size: 110"); + + output.clear(); + + e.indexed( 2); + e.encode(output); + e.indexed( 7); + e.encode(output); + e.indexed( 5); + e.encode(output); + e.indexed(63); + e.encode(output); + e.literalWithIndexing("custom-key", true, "custom-value", true); + e.encode(output); + + output.flip(); + + test(e, output, + + "8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925\n" + + "a849 e95b b8e8 b4bf", + + "[ 1] (s = 54) custom-key: custom-value\n" + + "[ 2] (s = 53) cache-control: no-cache\n" + + "[ 3] (s = 57) :authority: www.example.com\n" + + " Table size: 164"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.5 + // + @Test + public void example7() { + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + ByteBuffer output = ByteBuffer.allocate(128); + // @formatter:off + e.literalWithIndexing( 8, "302", false); + e.encode(output); + e.literalWithIndexing(24, "private", false); + e.encode(output); + e.literalWithIndexing(33, "Mon, 21 Oct 2013 20:13:21 GMT", false); + e.encode(output); + e.literalWithIndexing(46, "https://www.example.com", false); + e.encode(output); + + output.flip(); + + test(e, output, + + "4803 3330 3258 0770 7269 7661 7465 611d\n" + + "4d6f 6e2c 2032 3120 4f63 7420 3230 3133\n" + + "2032 303a 3133 3a32 3120 474d 546e 1768\n" + + "7474 7073 3a2f 2f77 7777 2e65 7861 6d70\n" + + "6c65 2e63 6f6d", + + "[ 1] (s = 63) location: https://www.example.com\n" + + "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 3] (s = 52) cache-control: private\n" + + "[ 4] (s = 42) :status: 302\n" + + " Table size: 222"); + + output.clear(); + + e.literalWithIndexing( 8, "307", false); + e.encode(output); + e.indexed(65); + e.encode(output); + e.indexed(64); + e.encode(output); + e.indexed(63); + e.encode(output); + + output.flip(); + + test(e, output, + + "4803 3330 37c1 c0bf", + + "[ 1] (s = 42) :status: 307\n" + + "[ 2] (s = 63) location: https://www.example.com\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 4] (s = 52) cache-control: private\n" + + " Table size: 222"); + + output.clear(); + + e.indexed( 8); + e.encode(output); + e.indexed(65); + e.encode(output); + e.literalWithIndexing(33, "Mon, 21 Oct 2013 20:13:22 GMT", false); + e.encode(output); + e.indexed(64); + e.encode(output); + e.literalWithIndexing(26, "gzip", false); + e.encode(output); + e.literalWithIndexing(55, "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", false); + e.encode(output); + + output.flip(); + + test(e, output, + + "88c1 611d 4d6f 6e2c 2032 3120 4f63 7420\n" + + "3230 3133 2032 303a 3133 3a32 3220 474d\n" + + "54c0 5a04 677a 6970 7738 666f 6f3d 4153\n" + + "444a 4b48 514b 425a 584f 5157 454f 5049\n" + + "5541 5851 5745 4f49 553b 206d 6178 2d61\n" + + "6765 3d33 3630 303b 2076 6572 7369 6f6e\n" + + "3d31", + + "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + + "[ 2] (s = 52) content-encoding: gzip\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + " Table size: 215"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.6 + // + @Test + public void example8() { + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + ByteBuffer output = ByteBuffer.allocate(128); + // @formatter:off + e.literalWithIndexing( 8, "302", true); + e.encode(output); + e.literalWithIndexing(24, "private", true); + e.encode(output); + e.literalWithIndexing(33, "Mon, 21 Oct 2013 20:13:21 GMT", true); + e.encode(output); + e.literalWithIndexing(46, "https://www.example.com", true); + e.encode(output); + + output.flip(); + + test(e, output, + + "4882 6402 5885 aec3 771a 4b61 96d0 7abe\n" + + "9410 54d4 44a8 2005 9504 0b81 66e0 82a6\n" + + "2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8\n" + + "e9ae 82ae 43d3", + + "[ 1] (s = 63) location: https://www.example.com\n" + + "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 3] (s = 52) cache-control: private\n" + + "[ 4] (s = 42) :status: 302\n" + + " Table size: 222"); + + output.clear(); + + e.literalWithIndexing( 8, "307", true); + e.encode(output); + e.indexed(65); + e.encode(output); + e.indexed(64); + e.encode(output); + e.indexed(63); + e.encode(output); + + output.flip(); + + test(e, output, + + "4883 640e ffc1 c0bf", + + "[ 1] (s = 42) :status: 307\n" + + "[ 2] (s = 63) location: https://www.example.com\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 4] (s = 52) cache-control: private\n" + + " Table size: 222"); + + output.clear(); + + e.indexed( 8); + e.encode(output); + e.indexed(65); + e.encode(output); + e.literalWithIndexing(33, "Mon, 21 Oct 2013 20:13:22 GMT", true); + e.encode(output); + e.indexed(64); + e.encode(output); + e.literalWithIndexing(26, "gzip", true); + e.encode(output); + e.literalWithIndexing(55, "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", true); + e.encode(output); + + output.flip(); + + test(e, output, + + "88c1 6196 d07a be94 1054 d444 a820 0595\n" + + "040b 8166 e084 a62d 1bff c05a 839b d9ab\n" + + "77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b\n" + + "3960 d5af 2708 7f36 72c1 ab27 0fb5 291f\n" + + "9587 3160 65c0 03ed 4ee5 b106 3d50 07", + + "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + + "[ 2] (s = 52) content-encoding: gzip\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + " Table size: 215"); + // @formatter:on + } + + @Test + public void initialSizeUpdateDefaultEncoder() { + Function e = Encoder::new; + testSizeUpdate(e, 1024, asList(), asList(0)); + testSizeUpdate(e, 1024, asList(1024), asList(0)); + testSizeUpdate(e, 1024, asList(1024, 1024), asList(0)); + testSizeUpdate(e, 1024, asList(1024, 512), asList(0)); + testSizeUpdate(e, 1024, asList(512, 1024), asList(0)); + testSizeUpdate(e, 1024, asList(512, 2048), asList(0)); + } + + @Test + public void initialSizeUpdateCustomEncoder() { + Function e = EncoderTest::newCustomEncoder; + testSizeUpdate(e, 1024, asList(), asList(1024)); + testSizeUpdate(e, 1024, asList(1024), asList(1024)); + testSizeUpdate(e, 1024, asList(1024, 1024), asList(1024)); + testSizeUpdate(e, 1024, asList(1024, 512), asList(512)); + testSizeUpdate(e, 1024, asList(512, 1024), asList(1024)); + testSizeUpdate(e, 1024, asList(512, 2048), asList(2048)); + } + + @Test + public void seriesOfSizeUpdatesDefaultEncoder() { + Function e = c -> { + Encoder encoder = new Encoder(c); + drainInitialUpdate(encoder); + return encoder; + }; + testSizeUpdate(e, 0, asList(0), asList()); + testSizeUpdate(e, 1024, asList(1024), asList()); + testSizeUpdate(e, 1024, asList(2048), asList()); + testSizeUpdate(e, 1024, asList(512), asList()); + testSizeUpdate(e, 1024, asList(1024, 1024), asList()); + testSizeUpdate(e, 1024, asList(1024, 2048), asList()); + testSizeUpdate(e, 1024, asList(2048, 1024), asList()); + testSizeUpdate(e, 1024, asList(1024, 512), asList()); + testSizeUpdate(e, 1024, asList(512, 1024), asList()); + } + + // + // https://tools.ietf.org/html/rfc7541#section-4.2 + // + @Test + public void seriesOfSizeUpdatesCustomEncoder() { + Function e = c -> { + Encoder encoder = newCustomEncoder(c); + drainInitialUpdate(encoder); + return encoder; + }; + testSizeUpdate(e, 0, asList(0), asList()); + testSizeUpdate(e, 1024, asList(1024), asList()); + testSizeUpdate(e, 1024, asList(2048), asList(2048)); + testSizeUpdate(e, 1024, asList(512), asList(512)); + testSizeUpdate(e, 1024, asList(1024, 1024), asList()); + testSizeUpdate(e, 1024, asList(1024, 2048), asList(2048)); + testSizeUpdate(e, 1024, asList(2048, 1024), asList()); + testSizeUpdate(e, 1024, asList(1024, 512), asList(512)); + testSizeUpdate(e, 1024, asList(512, 1024), asList(512, 1024)); + } + + @Test + public void callSequenceViolations() { + { // Hasn't set up a header + Encoder e = new Encoder(0); + assertVoidThrows(IllegalStateException.class, () -> e.encode(ByteBuffer.allocate(16))); + } + { // Can't set up header while there's an unfinished encoding + Encoder e = new Encoder(0); + e.indexed(32); + assertVoidThrows(IllegalStateException.class, () -> e.indexed(32)); + } + { // Can't setMaxCapacity while there's an unfinished encoding + Encoder e = new Encoder(0); + e.indexed(32); + assertVoidThrows(IllegalStateException.class, () -> e.setMaxCapacity(512)); + } + { // Hasn't set up a header + Encoder e = new Encoder(0); + e.setMaxCapacity(256); + assertVoidThrows(IllegalStateException.class, () -> e.encode(ByteBuffer.allocate(16))); + } + { // Hasn't set up a header after the previous encoding + Encoder e = new Encoder(0); + e.indexed(0); + boolean encoded = e.encode(ByteBuffer.allocate(16)); + assertTrue(encoded); // assumption + assertVoidThrows(IllegalStateException.class, () -> e.encode(ByteBuffer.allocate(16))); + } + } + + private static void test(Encoder encoder, + String expectedTableState, + String expectedHexdump) { + + ByteBuffer b = ByteBuffer.allocate(128); + encoder.encode(b); + b.flip(); + test(encoder, b, expectedTableState, expectedHexdump); + } + + private static void test(Encoder encoder, + ByteBuffer output, + String expectedHexdump, + String expectedTableState) { + + String actualTableState = encoder.getHeaderTable().getStateString(); + assertEquals(actualTableState, expectedTableState); + + String actualHexdump = toHexdump(output); + assertEquals(actualHexdump, expectedHexdump.replaceAll("\\n", " ")); + } + + // initial size - the size encoder is constructed with + // updates - a sequence of values for consecutive calls to encoder.setMaxCapacity + // expected - a sequence of values expected to be decoded by a decoder + private void testSizeUpdate(Function encoder, + int initialSize, + List updates, + List expected) { + Encoder e = encoder.apply(initialSize); + updates.forEach(e::setMaxCapacity); + ByteBuffer b = ByteBuffer.allocate(64); + e.header("a", "b"); + e.encode(b); + b.flip(); + Decoder d = new Decoder(updates.isEmpty() ? initialSize : Collections.max(updates)); + List actual = new ArrayList<>(); + d.decode(b, true, new DecodingCallback() { + @Override + public void onDecoded(CharSequence name, CharSequence value) { } + + @Override + public void onSizeUpdate(int capacity) { + actual.add(capacity); + } + }); + assertEquals(actual, expected); + } + + // + // Default encoder does not need any table, therefore a subclass that + // behaves differently is needed + // + private static Encoder newCustomEncoder(int maxCapacity) { + return new Encoder(maxCapacity) { + @Override + protected int calculateCapacity(int maxCapacity) { + return maxCapacity; + } + }; + } + + private static void drainInitialUpdate(Encoder e) { + ByteBuffer b = ByteBuffer.allocate(4); + e.header("a", "b"); + boolean done; + do { + done = e.encode(b); + b.flip(); + } while (!done); + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HeaderTableTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HeaderTableTest.java new file mode 100644 index 00000000000..1bc12029ca6 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HeaderTableTest.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; +import sun.net.httpclient.hpack.HeaderTable.HeaderField; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.lang.String.format; +import static org.testng.Assert.assertEquals; +import static sun.net.httpclient.hpack.TestHelper.*; + +public class HeaderTableTest { + + // + // https://tools.ietf.org/html/rfc7541#appendix-A + // + // @formatter:off + private static final String SPEC = + " | 1 | :authority | |\n" + + " | 2 | :method | GET |\n" + + " | 3 | :method | POST |\n" + + " | 4 | :path | / |\n" + + " | 5 | :path | /index.html |\n" + + " | 6 | :scheme | http |\n" + + " | 7 | :scheme | https |\n" + + " | 8 | :status | 200 |\n" + + " | 9 | :status | 204 |\n" + + " | 10 | :status | 206 |\n" + + " | 11 | :status | 304 |\n" + + " | 12 | :status | 400 |\n" + + " | 13 | :status | 404 |\n" + + " | 14 | :status | 500 |\n" + + " | 15 | accept-charset | |\n" + + " | 16 | accept-encoding | gzip, deflate |\n" + + " | 17 | accept-language | |\n" + + " | 18 | accept-ranges | |\n" + + " | 19 | accept | |\n" + + " | 20 | access-control-allow-origin | |\n" + + " | 21 | age | |\n" + + " | 22 | allow | |\n" + + " | 23 | authorization | |\n" + + " | 24 | cache-control | |\n" + + " | 25 | content-disposition | |\n" + + " | 26 | content-encoding | |\n" + + " | 27 | content-language | |\n" + + " | 28 | content-length | |\n" + + " | 29 | content-location | |\n" + + " | 30 | content-range | |\n" + + " | 31 | content-type | |\n" + + " | 32 | cookie | |\n" + + " | 33 | date | |\n" + + " | 34 | etag | |\n" + + " | 35 | expect | |\n" + + " | 36 | expires | |\n" + + " | 37 | from | |\n" + + " | 38 | host | |\n" + + " | 39 | if-match | |\n" + + " | 40 | if-modified-since | |\n" + + " | 41 | if-none-match | |\n" + + " | 42 | if-range | |\n" + + " | 43 | if-unmodified-since | |\n" + + " | 44 | last-modified | |\n" + + " | 45 | link | |\n" + + " | 46 | location | |\n" + + " | 47 | max-forwards | |\n" + + " | 48 | proxy-authenticate | |\n" + + " | 49 | proxy-authorization | |\n" + + " | 50 | range | |\n" + + " | 51 | referer | |\n" + + " | 52 | refresh | |\n" + + " | 53 | retry-after | |\n" + + " | 54 | server | |\n" + + " | 55 | set-cookie | |\n" + + " | 56 | strict-transport-security | |\n" + + " | 57 | transfer-encoding | |\n" + + " | 58 | user-agent | |\n" + + " | 59 | vary | |\n" + + " | 60 | via | |\n" + + " | 61 | www-authenticate | |\n"; + // @formatter:on + + private static final int STATIC_TABLE_LENGTH = createStaticEntries().size(); + private final Random rnd = newRandom(); + + @Test + public void staticData() { + HeaderTable table = new HeaderTable(0); + Map staticHeaderFields = createStaticEntries(); + + Map minimalIndexes = new HashMap<>(); + + for (Map.Entry e : staticHeaderFields.entrySet()) { + Integer idx = e.getKey(); + String hName = e.getValue().name; + Integer midx = minimalIndexes.get(hName); + if (midx == null) { + minimalIndexes.put(hName, idx); + } else { + minimalIndexes.put(hName, Math.min(idx, midx)); + } + } + + staticHeaderFields.entrySet().forEach( + e -> { + // lookup + HeaderField actualHeaderField = table.get(e.getKey()); + HeaderField expectedHeaderField = e.getValue(); + assertEquals(actualHeaderField, expectedHeaderField); + + // reverse lookup (name, value) + String hName = expectedHeaderField.name; + String hValue = expectedHeaderField.value; + int expectedIndex = e.getKey(); + int actualIndex = table.indexOf(hName, hValue); + + assertEquals(actualIndex, expectedIndex); + + // reverse lookup (name) + int expectedMinimalIndex = minimalIndexes.get(hName); + int actualMinimalIndex = table.indexOf(hName, "blah-blah"); + + assertEquals(-actualMinimalIndex, expectedMinimalIndex); + } + ); + } + + @Test + public void constructorSetsMaxSize() { + int size = rnd.nextInt(64); + HeaderTable t = new HeaderTable(size); + assertEquals(t.size(), 0); + assertEquals(t.maxSize(), size); + } + + @Test + public void negativeMaximumSize() { + int maxSize = -(rnd.nextInt(100) + 1); // [-100, -1] + IllegalArgumentException e = + assertVoidThrows(IllegalArgumentException.class, + () -> new HeaderTable(0).setMaxSize(maxSize)); + assertExceptionMessageContains(e, "maxSize"); + } + + @Test + public void zeroMaximumSize() { + HeaderTable table = new HeaderTable(0); + table.setMaxSize(0); + assertEquals(table.maxSize(), 0); + } + + @Test + public void negativeIndex() { + int idx = -(rnd.nextInt(256) + 1); // [-256, -1] + IllegalArgumentException e = + assertVoidThrows(IllegalArgumentException.class, + () -> new HeaderTable(0).get(idx)); + assertExceptionMessageContains(e, "index"); + } + + @Test + public void zeroIndex() { + IllegalArgumentException e = + assertThrows(IllegalArgumentException.class, + () -> new HeaderTable(0).get(0)); + assertExceptionMessageContains(e, "index"); + } + + @Test + public void length() { + HeaderTable table = new HeaderTable(0); + assertEquals(table.length(), STATIC_TABLE_LENGTH); + } + + @Test + public void indexOutsideStaticRange() { + HeaderTable table = new HeaderTable(0); + int idx = table.length() + (rnd.nextInt(256) + 1); + IllegalArgumentException e = + assertThrows(IllegalArgumentException.class, + () -> table.get(idx)); + assertExceptionMessageContains(e, "index"); + } + + @Test + public void entryPutAfterStaticArea() { + HeaderTable table = new HeaderTable(256); + int idx = table.length() + 1; + assertThrows(IllegalArgumentException.class, () -> table.get(idx)); + + byte[] bytes = new byte[32]; + rnd.nextBytes(bytes); + String name = new String(bytes, StandardCharsets.ISO_8859_1); + String value = "custom-value"; + + table.put(name, value); + HeaderField f = table.get(idx); + assertEquals(name, f.name); + assertEquals(value, f.value); + } + + @Test + public void staticTableHasZeroSize() { + HeaderTable table = new HeaderTable(0); + assertEquals(0, table.size()); + } + + @Test + public void lowerIndexPriority() { + HeaderTable table = new HeaderTable(256); + int oldLength = table.length(); + table.put("bender", "rodriguez"); + table.put("bender", "rodriguez"); + table.put("bender", "rodriguez"); + + assertEquals(table.length(), oldLength + 3); // more like an assumption + int i = table.indexOf("bender", "rodriguez"); + assertEquals(oldLength + 1, i); + } + + @Test + public void lowerIndexPriority2() { + HeaderTable table = new HeaderTable(256); + int oldLength = table.length(); + int idx = rnd.nextInt(oldLength) + 1; + HeaderField f = table.get(idx); + table.put(f.name, f.value); + assertEquals(table.length(), oldLength + 1); + int i = table.indexOf(f.name, f.value); + assertEquals(idx, i); + } + + // TODO: negative indexes check + // TODO: ensure full table clearance when adding huge header field + // TODO: ensure eviction deletes minimum needed entries, not more + + @Test + public void fifo() { + HeaderTable t = new HeaderTable(Integer.MAX_VALUE); + // Let's add a series of header fields + int NUM_HEADERS = 32; + for (int i = 1; i <= NUM_HEADERS; i++) { + String s = String.valueOf(i); + t.put(s, s); + } + // They MUST appear in a FIFO order: + // newer entries are at lower indexes + // older entries are at higher indexes + for (int j = 1; j <= NUM_HEADERS; j++) { + HeaderField f = t.get(STATIC_TABLE_LENGTH + j); + int actualName = Integer.parseInt(f.name); + int expectedName = NUM_HEADERS - j + 1; + assertEquals(expectedName, actualName); + } + // Entries MUST be evicted in the order they were added: + // the newer the entry the later it is evicted + for (int k = 1; k <= NUM_HEADERS; k++) { + HeaderField f = t.evictEntry(); + assertEquals(String.valueOf(k), f.name); + } + } + + @Test + public void indexOf() { + HeaderTable t = new HeaderTable(Integer.MAX_VALUE); + // Let's put a series of header fields + int NUM_HEADERS = 32; + for (int i = 1; i <= NUM_HEADERS; i++) { + String s = String.valueOf(i); + t.put(s, s); + } + // and verify indexOf (reverse lookup) returns correct indexes for + // full lookup + for (int j = 1; j <= NUM_HEADERS; j++) { + String s = String.valueOf(j); + int actualIndex = t.indexOf(s, s); + int expectedIndex = STATIC_TABLE_LENGTH + NUM_HEADERS - j + 1; + assertEquals(expectedIndex, actualIndex); + } + // as well as for just a name lookup + for (int j = 1; j <= NUM_HEADERS; j++) { + String s = String.valueOf(j); + int actualIndex = t.indexOf(s, "blah"); + int expectedIndex = -(STATIC_TABLE_LENGTH + NUM_HEADERS - j + 1); + assertEquals(expectedIndex, actualIndex); + } + // lookup for non-existent name returns 0 + assertEquals(0, t.indexOf("chupacabra", "1")); + } + + @Test + public void testToString() { + HeaderTable table = new HeaderTable(0); + { + table.setMaxSize(2048); + assertEquals("entries: 0; used 0/2048 (0.0%)", table.toString()); + } + + { + String name = "custom-name"; + String value = "custom-value"; + int size = 512; + + table.setMaxSize(size); + table.put(name, value); + String s = table.toString(); + + int used = name.length() + value.length() + 32; + double ratio = used * 100.0 / size; + + String expected = format("entries: 1; used %s/%s (%.1f%%)", used, size, ratio); + assertEquals(expected, s); + } + + { + table.setMaxSize(78); + table.put(":method", ""); + table.put(":status", ""); + String s = table.toString(); + assertEquals("entries: 2; used 78/78 (100.0%)", s); + } + } + + @Test + public void stateString() { + HeaderTable table = new HeaderTable(256); + table.put("custom-key", "custom-header"); + // @formatter:off + assertEquals("[ 1] (s = 55) custom-key: custom-header\n" + + " Table size: 55", table.getStateString()); + // @formatter:on + } + + private static Map createStaticEntries() { + Pattern line = Pattern.compile( + "\\|\\s*(?\\d+?)\\s*\\|\\s*(?.+?)\\s*\\|\\s*(?.*?)\\s*\\|"); + Matcher m = line.matcher(SPEC); + Map result = new HashMap<>(); + while (m.find()) { + int index = Integer.parseInt(m.group("index")); + String name = m.group("name"); + String value = m.group("value"); + HeaderField f = new HeaderField(name, value); + result.put(index, f); + } + return Collections.unmodifiableMap(result); // lol + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HuffmanTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HuffmanTest.java new file mode 100644 index 00000000000..502c7051a79 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HuffmanTest.java @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.nio.ByteBuffer; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.lang.Integer.parseInt; +import static org.testng.Assert.*; + +public final class HuffmanTest { + + // + // https://tools.ietf.org/html/rfc7541#appendix-B + // + private static final String SPEC = + // @formatter:off + " code as bits as hex len\n" + + " sym aligned to MSB aligned in\n" + + " to LSB bits\n" + + " ( 0) |11111111|11000 1ff8 [13]\n" + + " ( 1) |11111111|11111111|1011000 7fffd8 [23]\n" + + " ( 2) |11111111|11111111|11111110|0010 fffffe2 [28]\n" + + " ( 3) |11111111|11111111|11111110|0011 fffffe3 [28]\n" + + " ( 4) |11111111|11111111|11111110|0100 fffffe4 [28]\n" + + " ( 5) |11111111|11111111|11111110|0101 fffffe5 [28]\n" + + " ( 6) |11111111|11111111|11111110|0110 fffffe6 [28]\n" + + " ( 7) |11111111|11111111|11111110|0111 fffffe7 [28]\n" + + " ( 8) |11111111|11111111|11111110|1000 fffffe8 [28]\n" + + " ( 9) |11111111|11111111|11101010 ffffea [24]\n" + + " ( 10) |11111111|11111111|11111111|111100 3ffffffc [30]\n" + + " ( 11) |11111111|11111111|11111110|1001 fffffe9 [28]\n" + + " ( 12) |11111111|11111111|11111110|1010 fffffea [28]\n" + + " ( 13) |11111111|11111111|11111111|111101 3ffffffd [30]\n" + + " ( 14) |11111111|11111111|11111110|1011 fffffeb [28]\n" + + " ( 15) |11111111|11111111|11111110|1100 fffffec [28]\n" + + " ( 16) |11111111|11111111|11111110|1101 fffffed [28]\n" + + " ( 17) |11111111|11111111|11111110|1110 fffffee [28]\n" + + " ( 18) |11111111|11111111|11111110|1111 fffffef [28]\n" + + " ( 19) |11111111|11111111|11111111|0000 ffffff0 [28]\n" + + " ( 20) |11111111|11111111|11111111|0001 ffffff1 [28]\n" + + " ( 21) |11111111|11111111|11111111|0010 ffffff2 [28]\n" + + " ( 22) |11111111|11111111|11111111|111110 3ffffffe [30]\n" + + " ( 23) |11111111|11111111|11111111|0011 ffffff3 [28]\n" + + " ( 24) |11111111|11111111|11111111|0100 ffffff4 [28]\n" + + " ( 25) |11111111|11111111|11111111|0101 ffffff5 [28]\n" + + " ( 26) |11111111|11111111|11111111|0110 ffffff6 [28]\n" + + " ( 27) |11111111|11111111|11111111|0111 ffffff7 [28]\n" + + " ( 28) |11111111|11111111|11111111|1000 ffffff8 [28]\n" + + " ( 29) |11111111|11111111|11111111|1001 ffffff9 [28]\n" + + " ( 30) |11111111|11111111|11111111|1010 ffffffa [28]\n" + + " ( 31) |11111111|11111111|11111111|1011 ffffffb [28]\n" + + " ' ' ( 32) |010100 14 [ 6]\n" + + " '!' ( 33) |11111110|00 3f8 [10]\n" + + " '\"' ( 34) |11111110|01 3f9 [10]\n" + + " '#' ( 35) |11111111|1010 ffa [12]\n" + + " '$' ( 36) |11111111|11001 1ff9 [13]\n" + + " '%' ( 37) |010101 15 [ 6]\n" + + " '&' ( 38) |11111000 f8 [ 8]\n" + + " ''' ( 39) |11111111|010 7fa [11]\n" + + " '(' ( 40) |11111110|10 3fa [10]\n" + + " ')' ( 41) |11111110|11 3fb [10]\n" + + " '*' ( 42) |11111001 f9 [ 8]\n" + + " '+' ( 43) |11111111|011 7fb [11]\n" + + " ',' ( 44) |11111010 fa [ 8]\n" + + " '-' ( 45) |010110 16 [ 6]\n" + + " '.' ( 46) |010111 17 [ 6]\n" + + " '/' ( 47) |011000 18 [ 6]\n" + + " '0' ( 48) |00000 0 [ 5]\n" + + " '1' ( 49) |00001 1 [ 5]\n" + + " '2' ( 50) |00010 2 [ 5]\n" + + " '3' ( 51) |011001 19 [ 6]\n" + + " '4' ( 52) |011010 1a [ 6]\n" + + " '5' ( 53) |011011 1b [ 6]\n" + + " '6' ( 54) |011100 1c [ 6]\n" + + " '7' ( 55) |011101 1d [ 6]\n" + + " '8' ( 56) |011110 1e [ 6]\n" + + " '9' ( 57) |011111 1f [ 6]\n" + + " ':' ( 58) |1011100 5c [ 7]\n" + + " ';' ( 59) |11111011 fb [ 8]\n" + + " '<' ( 60) |11111111|1111100 7ffc [15]\n" + + " '=' ( 61) |100000 20 [ 6]\n" + + " '>' ( 62) |11111111|1011 ffb [12]\n" + + " '?' ( 63) |11111111|00 3fc [10]\n" + + " '@' ( 64) |11111111|11010 1ffa [13]\n" + + " 'A' ( 65) |100001 21 [ 6]\n" + + " 'B' ( 66) |1011101 5d [ 7]\n" + + " 'C' ( 67) |1011110 5e [ 7]\n" + + " 'D' ( 68) |1011111 5f [ 7]\n" + + " 'E' ( 69) |1100000 60 [ 7]\n" + + " 'F' ( 70) |1100001 61 [ 7]\n" + + " 'G' ( 71) |1100010 62 [ 7]\n" + + " 'H' ( 72) |1100011 63 [ 7]\n" + + " 'I' ( 73) |1100100 64 [ 7]\n" + + " 'J' ( 74) |1100101 65 [ 7]\n" + + " 'K' ( 75) |1100110 66 [ 7]\n" + + " 'L' ( 76) |1100111 67 [ 7]\n" + + " 'M' ( 77) |1101000 68 [ 7]\n" + + " 'N' ( 78) |1101001 69 [ 7]\n" + + " 'O' ( 79) |1101010 6a [ 7]\n" + + " 'P' ( 80) |1101011 6b [ 7]\n" + + " 'Q' ( 81) |1101100 6c [ 7]\n" + + " 'R' ( 82) |1101101 6d [ 7]\n" + + " 'S' ( 83) |1101110 6e [ 7]\n" + + " 'T' ( 84) |1101111 6f [ 7]\n" + + " 'U' ( 85) |1110000 70 [ 7]\n" + + " 'V' ( 86) |1110001 71 [ 7]\n" + + " 'W' ( 87) |1110010 72 [ 7]\n" + + " 'X' ( 88) |11111100 fc [ 8]\n" + + " 'Y' ( 89) |1110011 73 [ 7]\n" + + " 'Z' ( 90) |11111101 fd [ 8]\n" + + " '[' ( 91) |11111111|11011 1ffb [13]\n" + + " '\\' ( 92) |11111111|11111110|000 7fff0 [19]\n" + + " ']' ( 93) |11111111|11100 1ffc [13]\n" + + " '^' ( 94) |11111111|111100 3ffc [14]\n" + + " '_' ( 95) |100010 22 [ 6]\n" + + " '`' ( 96) |11111111|1111101 7ffd [15]\n" + + " 'a' ( 97) |00011 3 [ 5]\n" + + " 'b' ( 98) |100011 23 [ 6]\n" + + " 'c' ( 99) |00100 4 [ 5]\n" + + " 'd' (100) |100100 24 [ 6]\n" + + " 'e' (101) |00101 5 [ 5]\n" + + " 'f' (102) |100101 25 [ 6]\n" + + " 'g' (103) |100110 26 [ 6]\n" + + " 'h' (104) |100111 27 [ 6]\n" + + " 'i' (105) |00110 6 [ 5]\n" + + " 'j' (106) |1110100 74 [ 7]\n" + + " 'k' (107) |1110101 75 [ 7]\n" + + " 'l' (108) |101000 28 [ 6]\n" + + " 'm' (109) |101001 29 [ 6]\n" + + " 'n' (110) |101010 2a [ 6]\n" + + " 'o' (111) |00111 7 [ 5]\n" + + " 'p' (112) |101011 2b [ 6]\n" + + " 'q' (113) |1110110 76 [ 7]\n" + + " 'r' (114) |101100 2c [ 6]\n" + + " 's' (115) |01000 8 [ 5]\n" + + " 't' (116) |01001 9 [ 5]\n" + + " 'u' (117) |101101 2d [ 6]\n" + + " 'v' (118) |1110111 77 [ 7]\n" + + " 'w' (119) |1111000 78 [ 7]\n" + + " 'x' (120) |1111001 79 [ 7]\n" + + " 'y' (121) |1111010 7a [ 7]\n" + + " 'z' (122) |1111011 7b [ 7]\n" + + " '{' (123) |11111111|1111110 7ffe [15]\n" + + " '|' (124) |11111111|100 7fc [11]\n" + + " '}' (125) |11111111|111101 3ffd [14]\n" + + " '~' (126) |11111111|11101 1ffd [13]\n" + + " (127) |11111111|11111111|11111111|1100 ffffffc [28]\n" + + " (128) |11111111|11111110|0110 fffe6 [20]\n" + + " (129) |11111111|11111111|010010 3fffd2 [22]\n" + + " (130) |11111111|11111110|0111 fffe7 [20]\n" + + " (131) |11111111|11111110|1000 fffe8 [20]\n" + + " (132) |11111111|11111111|010011 3fffd3 [22]\n" + + " (133) |11111111|11111111|010100 3fffd4 [22]\n" + + " (134) |11111111|11111111|010101 3fffd5 [22]\n" + + " (135) |11111111|11111111|1011001 7fffd9 [23]\n" + + " (136) |11111111|11111111|010110 3fffd6 [22]\n" + + " (137) |11111111|11111111|1011010 7fffda [23]\n" + + " (138) |11111111|11111111|1011011 7fffdb [23]\n" + + " (139) |11111111|11111111|1011100 7fffdc [23]\n" + + " (140) |11111111|11111111|1011101 7fffdd [23]\n" + + " (141) |11111111|11111111|1011110 7fffde [23]\n" + + " (142) |11111111|11111111|11101011 ffffeb [24]\n" + + " (143) |11111111|11111111|1011111 7fffdf [23]\n" + + " (144) |11111111|11111111|11101100 ffffec [24]\n" + + " (145) |11111111|11111111|11101101 ffffed [24]\n" + + " (146) |11111111|11111111|010111 3fffd7 [22]\n" + + " (147) |11111111|11111111|1100000 7fffe0 [23]\n" + + " (148) |11111111|11111111|11101110 ffffee [24]\n" + + " (149) |11111111|11111111|1100001 7fffe1 [23]\n" + + " (150) |11111111|11111111|1100010 7fffe2 [23]\n" + + " (151) |11111111|11111111|1100011 7fffe3 [23]\n" + + " (152) |11111111|11111111|1100100 7fffe4 [23]\n" + + " (153) |11111111|11111110|11100 1fffdc [21]\n" + + " (154) |11111111|11111111|011000 3fffd8 [22]\n" + + " (155) |11111111|11111111|1100101 7fffe5 [23]\n" + + " (156) |11111111|11111111|011001 3fffd9 [22]\n" + + " (157) |11111111|11111111|1100110 7fffe6 [23]\n" + + " (158) |11111111|11111111|1100111 7fffe7 [23]\n" + + " (159) |11111111|11111111|11101111 ffffef [24]\n" + + " (160) |11111111|11111111|011010 3fffda [22]\n" + + " (161) |11111111|11111110|11101 1fffdd [21]\n" + + " (162) |11111111|11111110|1001 fffe9 [20]\n" + + " (163) |11111111|11111111|011011 3fffdb [22]\n" + + " (164) |11111111|11111111|011100 3fffdc [22]\n" + + " (165) |11111111|11111111|1101000 7fffe8 [23]\n" + + " (166) |11111111|11111111|1101001 7fffe9 [23]\n" + + " (167) |11111111|11111110|11110 1fffde [21]\n" + + " (168) |11111111|11111111|1101010 7fffea [23]\n" + + " (169) |11111111|11111111|011101 3fffdd [22]\n" + + " (170) |11111111|11111111|011110 3fffde [22]\n" + + " (171) |11111111|11111111|11110000 fffff0 [24]\n" + + " (172) |11111111|11111110|11111 1fffdf [21]\n" + + " (173) |11111111|11111111|011111 3fffdf [22]\n" + + " (174) |11111111|11111111|1101011 7fffeb [23]\n" + + " (175) |11111111|11111111|1101100 7fffec [23]\n" + + " (176) |11111111|11111111|00000 1fffe0 [21]\n" + + " (177) |11111111|11111111|00001 1fffe1 [21]\n" + + " (178) |11111111|11111111|100000 3fffe0 [22]\n" + + " (179) |11111111|11111111|00010 1fffe2 [21]\n" + + " (180) |11111111|11111111|1101101 7fffed [23]\n" + + " (181) |11111111|11111111|100001 3fffe1 [22]\n" + + " (182) |11111111|11111111|1101110 7fffee [23]\n" + + " (183) |11111111|11111111|1101111 7fffef [23]\n" + + " (184) |11111111|11111110|1010 fffea [20]\n" + + " (185) |11111111|11111111|100010 3fffe2 [22]\n" + + " (186) |11111111|11111111|100011 3fffe3 [22]\n" + + " (187) |11111111|11111111|100100 3fffe4 [22]\n" + + " (188) |11111111|11111111|1110000 7ffff0 [23]\n" + + " (189) |11111111|11111111|100101 3fffe5 [22]\n" + + " (190) |11111111|11111111|100110 3fffe6 [22]\n" + + " (191) |11111111|11111111|1110001 7ffff1 [23]\n" + + " (192) |11111111|11111111|11111000|00 3ffffe0 [26]\n" + + " (193) |11111111|11111111|11111000|01 3ffffe1 [26]\n" + + " (194) |11111111|11111110|1011 fffeb [20]\n" + + " (195) |11111111|11111110|001 7fff1 [19]\n" + + " (196) |11111111|11111111|100111 3fffe7 [22]\n" + + " (197) |11111111|11111111|1110010 7ffff2 [23]\n" + + " (198) |11111111|11111111|101000 3fffe8 [22]\n" + + " (199) |11111111|11111111|11110110|0 1ffffec [25]\n" + + " (200) |11111111|11111111|11111000|10 3ffffe2 [26]\n" + + " (201) |11111111|11111111|11111000|11 3ffffe3 [26]\n" + + " (202) |11111111|11111111|11111001|00 3ffffe4 [26]\n" + + " (203) |11111111|11111111|11111011|110 7ffffde [27]\n" + + " (204) |11111111|11111111|11111011|111 7ffffdf [27]\n" + + " (205) |11111111|11111111|11111001|01 3ffffe5 [26]\n" + + " (206) |11111111|11111111|11110001 fffff1 [24]\n" + + " (207) |11111111|11111111|11110110|1 1ffffed [25]\n" + + " (208) |11111111|11111110|010 7fff2 [19]\n" + + " (209) |11111111|11111111|00011 1fffe3 [21]\n" + + " (210) |11111111|11111111|11111001|10 3ffffe6 [26]\n" + + " (211) |11111111|11111111|11111100|000 7ffffe0 [27]\n" + + " (212) |11111111|11111111|11111100|001 7ffffe1 [27]\n" + + " (213) |11111111|11111111|11111001|11 3ffffe7 [26]\n" + + " (214) |11111111|11111111|11111100|010 7ffffe2 [27]\n" + + " (215) |11111111|11111111|11110010 fffff2 [24]\n" + + " (216) |11111111|11111111|00100 1fffe4 [21]\n" + + " (217) |11111111|11111111|00101 1fffe5 [21]\n" + + " (218) |11111111|11111111|11111010|00 3ffffe8 [26]\n" + + " (219) |11111111|11111111|11111010|01 3ffffe9 [26]\n" + + " (220) |11111111|11111111|11111111|1101 ffffffd [28]\n" + + " (221) |11111111|11111111|11111100|011 7ffffe3 [27]\n" + + " (222) |11111111|11111111|11111100|100 7ffffe4 [27]\n" + + " (223) |11111111|11111111|11111100|101 7ffffe5 [27]\n" + + " (224) |11111111|11111110|1100 fffec [20]\n" + + " (225) |11111111|11111111|11110011 fffff3 [24]\n" + + " (226) |11111111|11111110|1101 fffed [20]\n" + + " (227) |11111111|11111111|00110 1fffe6 [21]\n" + + " (228) |11111111|11111111|101001 3fffe9 [22]\n" + + " (229) |11111111|11111111|00111 1fffe7 [21]\n" + + " (230) |11111111|11111111|01000 1fffe8 [21]\n" + + " (231) |11111111|11111111|1110011 7ffff3 [23]\n" + + " (232) |11111111|11111111|101010 3fffea [22]\n" + + " (233) |11111111|11111111|101011 3fffeb [22]\n" + + " (234) |11111111|11111111|11110111|0 1ffffee [25]\n" + + " (235) |11111111|11111111|11110111|1 1ffffef [25]\n" + + " (236) |11111111|11111111|11110100 fffff4 [24]\n" + + " (237) |11111111|11111111|11110101 fffff5 [24]\n" + + " (238) |11111111|11111111|11111010|10 3ffffea [26]\n" + + " (239) |11111111|11111111|1110100 7ffff4 [23]\n" + + " (240) |11111111|11111111|11111010|11 3ffffeb [26]\n" + + " (241) |11111111|11111111|11111100|110 7ffffe6 [27]\n" + + " (242) |11111111|11111111|11111011|00 3ffffec [26]\n" + + " (243) |11111111|11111111|11111011|01 3ffffed [26]\n" + + " (244) |11111111|11111111|11111100|111 7ffffe7 [27]\n" + + " (245) |11111111|11111111|11111101|000 7ffffe8 [27]\n" + + " (246) |11111111|11111111|11111101|001 7ffffe9 [27]\n" + + " (247) |11111111|11111111|11111101|010 7ffffea [27]\n" + + " (248) |11111111|11111111|11111101|011 7ffffeb [27]\n" + + " (249) |11111111|11111111|11111111|1110 ffffffe [28]\n" + + " (250) |11111111|11111111|11111101|100 7ffffec [27]\n" + + " (251) |11111111|11111111|11111101|101 7ffffed [27]\n" + + " (252) |11111111|11111111|11111101|110 7ffffee [27]\n" + + " (253) |11111111|11111111|11111101|111 7ffffef [27]\n" + + " (254) |11111111|11111111|11111110|000 7fffff0 [27]\n" + + " (255) |11111111|11111111|11111011|10 3ffffee [26]\n" + + " EOS (256) |11111111|11111111|11111111|111111 3fffffff [30]"; + // @formatter:on + + @Test + public void read_table() { + Pattern line = Pattern.compile( + "\\(\\s*(?\\d+)\\s*\\)\\s*(?(\\|(0|1)+)+)\\s*" + + "(?[0-9a-zA-Z]+)\\s*\\[\\s*(?\\d+)\\s*\\]"); + Matcher m = line.matcher(SPEC); + int i = 0; + while (m.find()) { + String ascii = m.group("ascii"); + String binary = m.group("binary").replaceAll("\\|", ""); + String hex = m.group("hex"); + String len = m.group("len"); + + // Several sanity checks for the data read from the table, just to + // make sure what we read makes sense + assertEquals(parseInt(len), binary.length()); + assertEquals(parseInt(binary, 2), parseInt(hex, 16)); + + int expected = parseInt(ascii); + + // TODO: find actual eos, do not hardcode it! + byte[] bytes = intToBytes(0x3fffffff, 30, + parseInt(hex, 16), parseInt(len)); + + StringBuilder actual = new StringBuilder(); + Huffman.Reader t = new Huffman.Reader(); + t.read(ByteBuffer.wrap(bytes), actual, false, true); + + // What has been read MUST represent a single symbol + assertEquals(actual.length(), 1, "ascii: " + ascii); + + // It's a lot more visual to compare char as codes rather than + // characters (as some of them might not be visible) + assertEquals(actual.charAt(0), expected); + i++; + } + assertEquals(i, 257); // 256 + EOS + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.4.1 + // + @Test + public void read_1() { + read("f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"); + } + + @Test + public void write_1() { + write("www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.4.2 + // + @Test + public void read_2() { + read("a8eb 1064 9cbf", "no-cache"); + } + + @Test + public void write_2() { + write("no-cache", "a8eb 1064 9cbf"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.4.3 + // + @Test + public void read_3() { + read("25a8 49e9 5ba9 7d7f", "custom-key"); + } + + @Test + public void write_3() { + write("custom-key", "25a8 49e9 5ba9 7d7f"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.4.3 + // + @Test + public void read_4() { + read("25a8 49e9 5bb8 e8b4 bf", "custom-value"); + } + + @Test + public void write_4() { + write("custom-value", "25a8 49e9 5bb8 e8b4 bf"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.1 + // + @Test + public void read_5() { + read("6402", "302"); + } + + @Test + public void write_5() { + write("302", "6402"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.1 + // + @Test + public void read_6() { + read("aec3 771a 4b", "private"); + } + + @Test + public void write_6() { + write("private", "aec3 771a 4b"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.1 + // + @Test + public void read_7() { + read("d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", + "Mon, 21 Oct 2013 20:13:21 GMT"); + } + + @Test + public void write_7() { + write("Mon, 21 Oct 2013 20:13:21 GMT", + "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.1 + // + @Test + public void read_8() { + read("9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", + "https://www.example.com"); + } + + @Test + public void write_8() { + write("https://www.example.com", + "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.2 + // + @Test + public void read_9() { + read("640e ff", "307"); + } + + @Test + public void write_9() { + write("307", "640e ff"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.3 + // + @Test + public void read_10() { + read("d07a be94 1054 d444 a820 0595 040b 8166 e084 a62d 1bff", + "Mon, 21 Oct 2013 20:13:22 GMT"); + } + + @Test + public void write_10() { + write("Mon, 21 Oct 2013 20:13:22 GMT", + "d07a be94 1054 d444 a820 0595 040b 8166 e084 a62d 1bff"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.3 + // + @Test + public void read_11() { + read("9bd9 ab", "gzip"); + } + + @Test + public void write_11() { + write("gzip", "9bd9 ab"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.3 + // + @Test + public void read_12() { + read("94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 " + + "d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 " + + "3160 65c0 03ed 4ee5 b106 3d50 07", + "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"); + } + + @Test + public void test_trie_has_no_empty_nodes() { + Huffman.Node root = Huffman.INSTANCE.getRoot(); + Stack backlog = new Stack<>(); + backlog.push(root); + while (!backlog.isEmpty()) { + Huffman.Node n = backlog.pop(); + // The only type of nodes we couldn't possibly catch during + // construction is an empty node: no children and no char + if (n.left != null) { + backlog.push(n.left); + } + if (n.right != null) { + backlog.push(n.right); + } + assertFalse(!n.charIsSet && n.left == null && n.right == null, + "Empty node in the trie"); + } + } + + @Test + public void test_trie_has_257_nodes() { + int count = 0; + Huffman.Node root = Huffman.INSTANCE.getRoot(); + Stack backlog = new Stack<>(); + backlog.push(root); + while (!backlog.isEmpty()) { + Huffman.Node n = backlog.pop(); + if (n.left != null) { + backlog.push(n.left); + } + if (n.right != null) { + backlog.push(n.right); + } + if (n.isLeaf()) { + count++; + } + } + assertEquals(count, 257); + } + + @Test + public void cant_encode_outside_byte() { + TestHelper.Block coding = + () -> new Huffman.Writer() + .from(((char) 256) + "", 0, 1) + .write(ByteBuffer.allocate(1)); + RuntimeException e = + TestHelper.assertVoidThrows(RuntimeException.class, coding); + TestHelper.assertExceptionMessageContains(e, "char"); + } + + private static void read(String hexdump, String decoded) { + ByteBuffer source = SpecHelper.toBytes(hexdump); + Appendable actual = new StringBuilder(); + new Huffman.Reader().read(source, actual, true); + assertEquals(actual.toString(), decoded); + } + + private static void write(String decoded, String hexdump) { + int n = Huffman.INSTANCE.lengthOf(decoded); + ByteBuffer destination = ByteBuffer.allocate(n); // Extra margin (1) to test having more bytes in the destination than needed is ok + Huffman.Writer writer = new Huffman.Writer(); + BuffersTestingKit.forEachSplit(destination, byteBuffers -> { + writer.from(decoded, 0, decoded.length()); + boolean written = false; + for (ByteBuffer b : byteBuffers) { + int pos = b.position(); + written = writer.write(b); + b.position(pos); + } + assertTrue(written); + ByteBuffer concated = BuffersTestingKit.concat(byteBuffers); + String actual = SpecHelper.toHexdump(concated); + assertEquals(actual, hexdump); + writer.reset(); + }); + } + + // + // It's not very pretty, yes I know that + // + // hex: + // + // |31|30|...|N-1|...|01|00| + // \ / + // codeLength + // + // hex <<= 32 - codeLength; (align to MSB): + // + // |31|30|...|32-N|...|01|00| + // \ / + // codeLength + // + // EOS: + // + // |31|30|...|M-1|...|01|00| + // \ / + // eosLength + // + // eos <<= 32 - eosLength; (align to MSB): + // + // pad with MSBs of EOS: + // + // |31|30|...|32-N|32-N-1|...|01|00| + // | 32|...| + // + // Finally, split into byte[] + // + private byte[] intToBytes(int eos, int eosLength, int hex, int codeLength) { + hex <<= 32 - codeLength; + eos >>= codeLength - (32 - eosLength); + hex |= eos; + int n = (int) Math.ceil(codeLength / 8.0); + byte[] result = new byte[n]; + for (int i = 0; i < n; i++) { + result[i] = (byte) (hex >> (32 - 8 * (i + 1))); + } + return result; + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/SpecHelper.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/SpecHelper.java new file mode 100644 index 00000000000..88bd906514e --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/SpecHelper.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +// +// THIS IS NOT A TEST +// +public final class SpecHelper { + + private SpecHelper() { + throw new AssertionError(); + } + + public static ByteBuffer toBytes(String hexdump) { + Pattern hexByte = Pattern.compile("[0-9a-fA-F]{2}"); + List bytes = new ArrayList<>(); + Matcher matcher = hexByte.matcher(hexdump); + while (matcher.find()) { + bytes.add(matcher.group(0)); + } + ByteBuffer result = ByteBuffer.allocate(bytes.size()); + for (String f : bytes) { + result.put((byte) Integer.parseInt(f, 16)); + } + result.flip(); + return result; + } + + public static String toHexdump(ByteBuffer bb) { + List words = new ArrayList<>(); + int i = 0; + while (bb.hasRemaining()) { + if (i % 2 == 0) { + words.add(""); + } + byte b = bb.get(); + String hex = Integer.toHexString(256 + Byte.toUnsignedInt(b)).substring(1); + words.set(i / 2, words.get(i / 2) + hex); + i++; + } + return words.stream().collect(Collectors.joining(" ")); + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/TestHelper.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/TestHelper.java new file mode 100644 index 00000000000..b042b5f4cee --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/TestHelper.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.util.Objects; +import java.util.Random; + +public final class TestHelper { + + public static Random newRandom() { + long seed = Long.getLong("jdk.test.lib.random.seed", System.currentTimeMillis()); + System.out.println("new java.util.Random(" + seed + ")"); + return new Random(seed); + } + + public static T assertVoidThrows(Class clazz, Block code) { + return assertThrows(clazz, () -> { + code.run(); + return null; + }); + } + + public static T assertThrows(Class clazz, ReturningBlock code) { + Objects.requireNonNull(clazz, "clazz == null"); + Objects.requireNonNull(code, "code == null"); + try { + code.run(); + } catch (Throwable t) { + if (clazz.isInstance(t)) { + return clazz.cast(t); + } + throw new AssertionError("Expected to catch exception of type " + + clazz.getCanonicalName() + ", instead caught " + + t.getClass().getCanonicalName(), t); + + } + throw new AssertionError( + "Expected to catch exception of type " + clazz.getCanonicalName() + + ", but caught nothing"); + } + + public static T assertDoesNotThrow(ReturningBlock code) { + Objects.requireNonNull(code, "code == null"); + try { + return code.run(); + } catch (Throwable t) { + throw new AssertionError( + "Expected code block to exit normally, instead " + + "caught " + t.getClass().getCanonicalName(), t); + } + } + + public static void assertVoidDoesNotThrow(Block code) { + Objects.requireNonNull(code, "code == null"); + try { + code.run(); + } catch (Throwable t) { + throw new AssertionError( + "Expected code block to exit normally, instead " + + "caught " + t.getClass().getCanonicalName(), t); + } + } + + + public static void assertExceptionMessageContains(Throwable t, + CharSequence firstSubsequence, + CharSequence... others) { + assertCharSequenceContains(t.getMessage(), firstSubsequence, others); + } + + public static void assertCharSequenceContains(CharSequence s, + CharSequence firstSubsequence, + CharSequence... others) { + if (s == null) { + throw new NullPointerException("Exception message is null"); + } + String str = s.toString(); + String missing = null; + if (!str.contains(firstSubsequence.toString())) { + missing = firstSubsequence.toString(); + } else { + for (CharSequence o : others) { + if (!str.contains(o.toString())) { + missing = o.toString(); + break; + } + } + } + if (missing != null) { + throw new AssertionError("CharSequence '" + s + "'" + " does not " + + "contain subsequence '" + missing + "'"); + } + } + + public interface ReturningBlock { + T run() throws Throwable; + } + + public interface Block { + void run() throws Throwable; + } + + // tests + + @Test + public void assertThrows() { + assertThrows(NullPointerException.class, () -> ((Object) null).toString()); + } + + @Test + public void assertThrowsWrongType() { + try { + assertThrows(IllegalArgumentException.class, () -> ((Object) null).toString()); + } catch (AssertionError e) { + Throwable cause = e.getCause(); + String message = e.getMessage(); + if (cause != null + && cause instanceof NullPointerException + && message != null + && message.contains("instead caught")) { + return; + } + } + throw new AssertionError(); + } + + @Test + public void assertThrowsNoneCaught() { + try { + assertThrows(IllegalArgumentException.class, () -> null); + } catch (AssertionError e) { + Throwable cause = e.getCause(); + String message = e.getMessage(); + if (cause == null + && message != null + && message.contains("but caught nothing")) { + return; + } + } + throw new AssertionError(); + } +} From 22da92970991109600870cacd41f3d30224c0e0b Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Mon, 18 Apr 2016 20:58:19 +0100 Subject: [PATCH 095/222] 8147553: Remove sun.misc.ManagedLocalsThread from java.management Reviewed-by: dfuchs --- .../jmx/remote/internal/ClientCommunicatorAdmin.java | 10 +++++----- .../sun/jmx/remote/internal/ClientNotifForwarder.java | 8 +++++--- .../jmx/remote/internal/ServerCommunicatorAdmin.java | 7 +++++-- .../classes/javax/management/monitor/Monitor.java | 7 ++++--- jdk/src/java.management/share/classes/module-info.java | 2 -- .../classes/sun/management/jdp/JdpController.java | 3 +-- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java index 85f248311cb..5df5c243782 100644 --- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java +++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java @@ -30,7 +30,6 @@ import java.io.InterruptedIOException; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; -import sun.misc.ManagedLocalsThread; public abstract class ClientCommunicatorAdmin { private static volatile long threadNo = 1; @@ -41,10 +40,11 @@ public abstract class ClientCommunicatorAdmin { if (period > 0) { checker = new Checker(); - Thread t = new ManagedLocalsThread( - checker, - "JMX client heartbeat " + (++threadNo) - ); + Thread t = new Thread(null, + checker, + "JMX client heartbeat " + (++threadNo), + 0, + false); t.setDaemon(true); t.start(); diff --git a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java index 05abd0ceeb5..e0860f8e1f0 100644 --- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java +++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java @@ -52,7 +52,6 @@ import javax.management.remote.TargetedNotification; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; import java.rmi.UnmarshalException; -import sun.misc.ManagedLocalsThread; public abstract class ClientNotifForwarder { @@ -91,7 +90,8 @@ public abstract class ClientNotifForwarder { throw new IllegalArgumentException("More than one command"); this.command = command; if (thread == null) { - thread = new ManagedLocalsThread( + thread = new Thread( + null, ()-> { while (true) { Runnable r; @@ -107,7 +107,9 @@ public abstract class ClientNotifForwarder { r.run(); } }, - "ClientNotifForwarder-" + ++threadId + "ClientNotifForwarder-" + ++threadId, + 0, + false ); thread.setDaemon(true); thread.start(); diff --git a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java index 6df86f5931b..74fbbd4c329 100644 --- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java +++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java @@ -27,7 +27,6 @@ package com.sun.jmx.remote.internal; import com.sun.jmx.remote.util.ClassLogger; -import sun.misc.ManagedLocalsThread; public abstract class ServerCommunicatorAdmin { public ServerCommunicatorAdmin(long timeout) { @@ -42,7 +41,11 @@ public abstract class ServerCommunicatorAdmin { timestamp = 0; if (timeout < Long.MAX_VALUE) { Runnable timeoutTask = new Timeout(); - final Thread t = new ManagedLocalsThread(timeoutTask); + final Thread t = new Thread(null, + timeoutTask, + "JMX-Server-Admin-Timeout", + 0, + false); t.setName("JMX server connection timeout " + t.getId()); // If you change this name you will need to change a unit test // (NoServerTimeoutTest) diff --git a/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java b/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java index 6276fb33b50..eb2a59ac14a 100644 --- a/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java +++ b/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java @@ -61,7 +61,6 @@ import javax.management.NotificationBroadcasterSupport; import javax.management.ObjectName; import javax.management.ReflectionException; import static javax.management.monitor.MonitorNotification.*; -import sun.misc.ManagedLocalsThread; /** * Defines the part common to all monitor MBeans. @@ -1637,10 +1636,12 @@ public abstract class Monitor } public Thread newThread(Runnable r) { - Thread t = new ManagedLocalsThread( + Thread t = new Thread( group, r, - namePrefix + threadNumber.getAndIncrement() + nameSuffix + namePrefix + threadNumber.getAndIncrement() + nameSuffix, + 0, + false ); t.setDaemon(true); diff --git a/jdk/src/java.management/share/classes/module-info.java b/jdk/src/java.management/share/classes/module-info.java index 811c2de91bd..8f7bd1b909e 100644 --- a/jdk/src/java.management/share/classes/module-info.java +++ b/jdk/src/java.management/share/classes/module-info.java @@ -27,8 +27,6 @@ module java.management { requires public java.rmi; requires java.logging; requires java.naming; - // 8147553 - requires jdk.unsupported; exports java.lang.management; exports javax.management; diff --git a/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java b/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java index 344d2db2b9e..f96227ce471 100644 --- a/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java +++ b/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java @@ -34,7 +34,6 @@ import java.lang.management.RuntimeMXBean; import java.lang.reflect.Field; import java.lang.reflect.Method; import sun.management.VMManagement; -import sun.misc.ManagedLocalsThread; /** * JdpController is responsible to create and manage a broadcast loop. @@ -219,7 +218,7 @@ public final class JdpController { controller = new JDPControllerRunner(bcast, packet, pause); - Thread t = new ManagedLocalsThread(controller, "JDP broadcaster"); + Thread t = new Thread(null, controller, "JDP broadcaster", 0, false); t.setDaemon(true); t.start(); } From 5a117b7e566eaf1269a29928d20daf985bb9e7d4 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Mon, 18 Apr 2016 20:58:21 +0100 Subject: [PATCH 096/222] 8153372: Remove sun.misc.ManagedLocalsThread from jdk.httpserver Reviewed-by: alanb --- jdk/src/jdk.httpserver/share/classes/module-info.java | 3 +-- .../share/classes/sun/net/httpserver/ServerImpl.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/jdk/src/jdk.httpserver/share/classes/module-info.java b/jdk/src/jdk.httpserver/share/classes/module-info.java index e71e6a3f3c8..e26758b66e9 100644 --- a/jdk/src/jdk.httpserver/share/classes/module-info.java +++ b/jdk/src/jdk.httpserver/share/classes/module-info.java @@ -25,8 +25,7 @@ module jdk.httpserver { requires java.logging; - // 8153372 - requires jdk.unsupported; + exports com.sun.net.httpserver; exports com.sun.net.httpserver.spi; uses com.sun.net.httpserver.spi.HttpServerProvider; diff --git a/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java b/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java index 1c3ac29f936..a8566e8f7b6 100644 --- a/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java +++ b/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java @@ -36,7 +36,6 @@ import javax.net.ssl.*; import com.sun.net.httpserver.*; import java.security.AccessController; import java.security.PrivilegedAction; -import sun.misc.ManagedLocalsThread; import sun.net.httpserver.HttpConnection.State; /** @@ -143,7 +142,7 @@ class ServerImpl implements TimeSource { if (executor == null) { executor = new DefaultExecutor(); } - dispatcherThread = new ManagedLocalsThread(dispatcher); + dispatcherThread = new Thread(null, dispatcher, "HTTP-Dispatcher", 0, false); started = true; dispatcherThread.start(); } From 78ca5988bc81d78012b2f7c260eb105960c9ad27 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Mon, 18 Apr 2016 20:58:30 +0100 Subject: [PATCH 097/222] 8153158: Remove sun.misc.ManagedLocalsThread from java.logging Reviewed-by: dfuchs, redestad --- .../share/classes/java/util/logging/LogManager.java | 4 ++-- jdk/src/java.logging/share/classes/module-info.java | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java index 81f3387be8c..e15add5a4f8 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java @@ -42,7 +42,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.misc.JavaAWTAccess; import jdk.internal.misc.SharedSecrets; -import sun.misc.ManagedLocalsThread; import sun.util.logging.internal.LoggingProviderImpl; /** @@ -254,9 +253,10 @@ public class LogManager { // This private class is used as a shutdown hook. // It does a "reset" to close all open handlers. - private class Cleaner extends ManagedLocalsThread { + private class Cleaner extends Thread { private Cleaner() { + super(null, null, "Logging-Cleaner", 0, false); /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */ diff --git a/jdk/src/java.logging/share/classes/module-info.java b/jdk/src/java.logging/share/classes/module-info.java index 0deda7677b5..47456e5ef5b 100644 --- a/jdk/src/java.logging/share/classes/module-info.java +++ b/jdk/src/java.logging/share/classes/module-info.java @@ -24,8 +24,6 @@ */ module java.logging { - // 8153158 - requires jdk.unsupported; exports java.util.logging; provides jdk.internal.logger.DefaultLoggerFinder with sun.util.logging.internal.LoggingProviderImpl; From ba908a90375f062ee7743c630ecbacdf749c38a6 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Mon, 18 Apr 2016 14:10:14 -0700 Subject: [PATCH 098/222] 8145468: update java.lang APIs with new deprecations Reviewed-by: alanb, psandoz, lancea, forax, scolebourne, chegar, martin --- .../share/classes/java/lang/Boolean.java | 28 ++++++++++------- .../share/classes/java/lang/Byte.java | 16 ++++++++-- .../share/classes/java/lang/Character.java | 26 +++++++++------- .../share/classes/java/lang/ClassLoader.java | 4 +-- .../share/classes/java/lang/Double.java | 16 ++++++++-- .../share/classes/java/lang/Float.java | 26 +++++++++++++--- .../share/classes/java/lang/Integer.java | 21 +++++++++---- .../share/classes/java/lang/Long.java | 14 ++++++++- .../share/classes/java/lang/Package.java | 2 +- .../share/classes/java/lang/Runtime.java | 9 ++++-- .../classes/java/lang/SecurityManager.java | 30 +++++++++++-------- .../share/classes/java/lang/Short.java | 14 ++++++++- .../share/classes/java/lang/String.java | 6 ++-- .../share/classes/java/lang/System.java | 3 +- .../share/classes/java/lang/Thread.java | 16 ++++++---- .../share/classes/java/lang/ThreadGroup.java | 8 ++--- .../classes/java/lang/invoke/MemberName.java | 1 + .../java/lang/reflect/ProxyGenerator.java | 2 +- .../share/classes/java/text/ChoiceFormat.java | 2 +- .../classes/java/text/DecimalFormat.java | 16 +++++----- .../util/concurrent/ThreadLocalRandom.java | 2 +- .../internal/org/objectweb/asm/Opcodes.java | 3 ++ .../classes/sun/nio/ch/InheritedChannel.java | 2 +- .../net/DualStackPlainDatagramSocketImpl.java | 2 +- .../sun/nio/ch/WindowsSelectorImpl.java | 6 ++-- .../security/krb5/internal/tools/Klist.java | 2 +- .../com/sun/rowset/CachedRowSetImpl.java | 8 ++--- .../sun/tools/jstat/ExpressionExecuter.java | 8 ++--- .../sun/tools/jstat/ExpressionResolver.java | 6 ++-- .../share/classes/sun/tools/jstat/Parser.java | 4 +-- .../sun/tools/example/debug/tty/Commands.java | 12 ++++---- .../example/debug/tty/MessageOutput.java | 2 +- 32 files changed, 211 insertions(+), 106 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/Boolean.java b/jdk/src/java.base/share/classes/java/lang/Boolean.java index b53995193f1..eeda751719c 100644 --- a/jdk/src/java.base/share/classes/java/lang/Boolean.java +++ b/jdk/src/java.base/share/classes/java/lang/Boolean.java @@ -79,13 +79,16 @@ public final class Boolean implements java.io.Serializable, * Allocates a {@code Boolean} object representing the * {@code value} argument. * - *

    Note: It is rarely appropriate to use this constructor. - * Unless a new instance is required, the static factory - * {@link #valueOf(boolean)} is generally a better choice. It is - * likely to yield significantly better space and time performance. - * * @param value the value of the {@code Boolean}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(boolean)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. + * Also consider using the final fields {@link #TRUE} and {@link #FALSE} + * if possible. */ + @Deprecated(since="9") public Boolean(boolean value) { this.value = value; } @@ -94,15 +97,18 @@ public final class Boolean implements java.io.Serializable, * Allocates a {@code Boolean} object representing the value * {@code true} if the string argument is not {@code null} * and is equal, ignoring case, to the string {@code "true"}. - * Otherwise, allocate a {@code Boolean} object representing the - * value {@code false}. Examples:

    - * {@code new Boolean("True")} produces a {@code Boolean} object - * that represents {@code true}.
    - * {@code new Boolean("yes")} produces a {@code Boolean} object - * that represents {@code false}. + * Otherwise, allocates a {@code Boolean} object representing the + * value {@code false}. * * @param s the string to be converted to a {@code Boolean}. + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseBoolean(String)} to convert a string to a + * {@code boolean} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Boolean} object. */ + @Deprecated(since="9") public Boolean(String s) { this(parseBoolean(s)); } diff --git a/jdk/src/java.base/share/classes/java/lang/Byte.java b/jdk/src/java.base/share/classes/java/lang/Byte.java index 51f687cb389..877af689556 100644 --- a/jdk/src/java.base/share/classes/java/lang/Byte.java +++ b/jdk/src/java.base/share/classes/java/lang/Byte.java @@ -297,7 +297,13 @@ public final class Byte extends Number implements Comparable { * * @param value the value to be represented by the * {@code Byte}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(byte)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Byte(byte value) { this.value = value; } @@ -311,10 +317,16 @@ public final class Byte extends Number implements Comparable { * * @param s the {@code String} to be converted to a * {@code Byte} - * @throws NumberFormatException If the {@code String} + * @throws NumberFormatException if the {@code String} * does not contain a parsable {@code byte}. - * @see java.lang.Byte#parseByte(java.lang.String, int) + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseByte(String)} to convert a string to a + * {@code byte} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Byte} object. */ + @Deprecated(since="9") public Byte(String s) throws NumberFormatException { this.value = parseByte(s, 10); } diff --git a/jdk/src/java.base/share/classes/java/lang/Character.java b/jdk/src/java.base/share/classes/java/lang/Character.java index ea42bfb3d6e..9f9e4de1972 100644 --- a/jdk/src/java.base/share/classes/java/lang/Character.java +++ b/jdk/src/java.base/share/classes/java/lang/Character.java @@ -1256,14 +1256,14 @@ class Character implements java.io.Serializable, Comparable { new UnicodeBlock("SPECIALS"); /** - * @deprecated As of J2SE 5, use {@link #HIGH_SURROGATES}, - * {@link #HIGH_PRIVATE_USE_SURROGATES}, and - * {@link #LOW_SURROGATES}. These new constants match - * the block definitions of the Unicode Standard. - * The {@link #of(char)} and {@link #of(int)} methods - * return the new constants, not SURROGATES_AREA. + * @deprecated + * Instead of {@code SURROGATES_AREA}, use {@link #HIGH_SURROGATES}, + * {@link #HIGH_PRIVATE_USE_SURROGATES}, and {@link #LOW_SURROGATES}. + * These constants match the block definitions of the Unicode Standard. + * The {@link #of(char)} and {@link #of(int)} methods return the + * standard constants. */ - @Deprecated + @Deprecated(since="1.5") public static final UnicodeBlock SURROGATES_AREA = new UnicodeBlock("SURROGATES_AREA"); @@ -7451,7 +7451,13 @@ class Character implements java.io.Serializable, Comparable { * * @param value the value to be represented by the * {@code Character} object. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(char)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Character(char value) { this.value = value; } @@ -8799,7 +8805,7 @@ class Character implements java.io.Serializable, Comparable { * @since 1.0.2 * @deprecated Replaced by isJavaIdentifierStart(char). */ - @Deprecated + @Deprecated(since="1.1") public static boolean isJavaLetter(char ch) { return isJavaIdentifierStart(ch); } @@ -8835,7 +8841,7 @@ class Character implements java.io.Serializable, Comparable { * @since 1.0.2 * @deprecated Replaced by isJavaIdentifierPart(char). */ - @Deprecated + @Deprecated(since="1.1") public static boolean isJavaLetterOrDigit(char ch) { return isJavaIdentifierPart(ch); } @@ -9580,7 +9586,7 @@ class Character implements java.io.Serializable, Comparable { * @see Character#isWhitespace(char) * @deprecated Replaced by isWhitespace(char). */ - @Deprecated + @Deprecated(since="1.1") public static boolean isSpace(char ch) { return (ch <= 0x0020) && (((((1L << 0x0009) | diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java index 33e5105bb3d..1fcd03b760f 100644 --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java @@ -727,7 +727,7 @@ public abstract class ClassLoader { * @deprecated Replaced by {@link #defineClass(String, byte[], int, int) * defineClass(String, byte[], int, int)} */ - @Deprecated + @Deprecated(since="1.1") protected final Class defineClass(byte[] b, int off, int len) throws ClassFormatError { @@ -2012,7 +2012,7 @@ public abstract class ClassLoader { * * @since 1.2 */ - @Deprecated + @Deprecated(since="9") protected Package getPackage(String name) { Package pkg = getDefinedPackage(name); if (pkg == null) { diff --git a/jdk/src/java.base/share/classes/java/lang/Double.java b/jdk/src/java.base/share/classes/java/lang/Double.java index 473b86dd909..75a227e5282 100644 --- a/jdk/src/java.base/share/classes/java/lang/Double.java +++ b/jdk/src/java.base/share/classes/java/lang/Double.java @@ -589,7 +589,13 @@ public final class Double extends Number implements Comparable { * represents the primitive {@code double} argument. * * @param value the value to be represented by the {@code Double}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(double)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Double(double value) { this.value = value; } @@ -601,10 +607,16 @@ public final class Double extends Number implements Comparable { * {@code double} value as if by the {@code valueOf} method. * * @param s a string to be converted to a {@code Double}. - * @throws NumberFormatException if the string does not contain a + * @throws NumberFormatException if the string does not contain a * parsable number. - * @see java.lang.Double#valueOf(java.lang.String) + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseDouble(String)} to convert a string to a + * {@code double} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Double} object. */ + @Deprecated(since="9") public Double(String s) throws NumberFormatException { value = parseDouble(s); } diff --git a/jdk/src/java.base/share/classes/java/lang/Float.java b/jdk/src/java.base/share/classes/java/lang/Float.java index 334d3d033da..60e08db7ad5 100644 --- a/jdk/src/java.base/share/classes/java/lang/Float.java +++ b/jdk/src/java.base/share/classes/java/lang/Float.java @@ -502,7 +502,13 @@ public final class Float extends Number implements Comparable { * represents the primitive {@code float} argument. * * @param value the value to be represented by the {@code Float}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(float)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Float(float value) { this.value = value; } @@ -512,7 +518,13 @@ public final class Float extends Number implements Comparable { * represents the argument converted to type {@code float}. * * @param value the value to be represented by the {@code Float}. + * + * @deprecated + * It is rarely appropriate to use this constructor. Instead, use the + * static factory method {@link #valueOf(float)} method as follows: + * {@code Float.valueOf((float)value)}. */ + @Deprecated(since="9") public Float(double value) { this.value = (float)value; } @@ -523,11 +535,17 @@ public final class Float extends Number implements Comparable { * represented by the string. The string is converted to a * {@code float} value as if by the {@code valueOf} method. * - * @param s a string to be converted to a {@code Float}. - * @throws NumberFormatException if the string does not contain a - * parsable number. - * @see java.lang.Float#valueOf(java.lang.String) + * @param s a string to be converted to a {@code Float}. + * @throws NumberFormatException if the string does not contain a + * parsable number. + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseFloat(String)} to convert a string to a + * {@code float} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Float} object. */ + @Deprecated(since="9") public Float(String s) throws NumberFormatException { value = parseFloat(s); } diff --git a/jdk/src/java.base/share/classes/java/lang/Integer.java b/jdk/src/java.base/share/classes/java/lang/Integer.java index 2a846c4d07f..7765d784e07 100644 --- a/jdk/src/java.base/share/classes/java/lang/Integer.java +++ b/jdk/src/java.base/share/classes/java/lang/Integer.java @@ -1106,7 +1106,13 @@ public final class Integer extends Number implements Comparable { * * @param value the value to be represented by the * {@code Integer} object. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(int)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Integer(int value) { this.value = value; } @@ -1118,12 +1124,17 @@ public final class Integer extends Number implements Comparable { * {@code int} value in exactly the manner used by the * {@code parseInt} method for radix 10. * - * @param s the {@code String} to be converted to an - * {@code Integer}. - * @exception NumberFormatException if the {@code String} does not - * contain a parsable integer. - * @see java.lang.Integer#parseInt(java.lang.String, int) + * @param s the {@code String} to be converted to an {@code Integer}. + * @throws NumberFormatException if the {@code String} does not + * contain a parsable integer. + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseInt(String)} to convert a string to a + * {@code int} primitive, or use {@link #valueOf(String)} + * to convert a string to an {@code Integer} object. */ + @Deprecated(since="9") public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); } diff --git a/jdk/src/java.base/share/classes/java/lang/Long.java b/jdk/src/java.base/share/classes/java/lang/Long.java index ae93a7ca827..793d15e53b2 100644 --- a/jdk/src/java.base/share/classes/java/lang/Long.java +++ b/jdk/src/java.base/share/classes/java/lang/Long.java @@ -1340,7 +1340,13 @@ public final class Long extends Number implements Comparable { * * @param value the value to be represented by the * {@code Long} object. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(long)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Long(long value) { this.value = value; } @@ -1356,8 +1362,14 @@ public final class Long extends Number implements Comparable { * {@code Long}. * @throws NumberFormatException if the {@code String} does not * contain a parsable {@code long}. - * @see java.lang.Long#parseLong(java.lang.String, int) + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseLong(String)} to convert a string to a + * {@code long} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Long} object. */ + @Deprecated(since="9") public Long(String s) throws NumberFormatException { this.value = parseLong(s, 10); } diff --git a/jdk/src/java.base/share/classes/java/lang/Package.java b/jdk/src/java.base/share/classes/java/lang/Package.java index 3b328ca199f..1aa9e98fbf2 100644 --- a/jdk/src/java.base/share/classes/java/lang/Package.java +++ b/jdk/src/java.base/share/classes/java/lang/Package.java @@ -333,7 +333,7 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated * @see ClassLoader#getDefinedPackage */ @CallerSensitive - @Deprecated + @Deprecated(since="9") @SuppressWarnings("deprecation") public static Package getPackage(String name) { ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); diff --git a/jdk/src/java.base/share/classes/java/lang/Runtime.java b/jdk/src/java.base/share/classes/java/lang/Runtime.java index 64b22de4bd6..a5deffc16b8 100644 --- a/jdk/src/java.base/share/classes/java/lang/Runtime.java +++ b/jdk/src/java.base/share/classes/java/lang/Runtime.java @@ -289,6 +289,7 @@ public class Runtime { * finalizers being called on live objects while other threads are * concurrently manipulating those objects, resulting in erratic * behavior or deadlock. + * This method is subject to removal in a future version of Java SE. * * @throws SecurityException * if a security manager exists and its {@code checkExit} @@ -299,7 +300,7 @@ public class Runtime { * @see java.lang.SecurityManager#checkExit(int) * @since 1.1 */ - @Deprecated + @Deprecated(since="1.2", forRemoval=true) public static void runFinalizersOnExit(boolean value) { SecurityManager security = System.getSecurityManager(); if (security != null) { @@ -894,8 +895,9 @@ public class Runtime { * stream in the local encoding into a character stream in Unicode is via * the {@code InputStreamReader} and {@code BufferedReader} * classes. + * This method is subject to removal in a future version of Java SE. */ - @Deprecated + @Deprecated(since="1.1", forRemoval=true) public InputStream getLocalizedInputStream(InputStream in) { return in; } @@ -915,6 +917,7 @@ public class Runtime { * Unicode character stream into a byte stream in the local encoding is via * the {@code OutputStreamWriter}, {@code BufferedWriter}, and * {@code PrintWriter} classes. + * This method is subject to removal in a future version of Java SE. * * @param out OutputStream to localize * @return a localized output stream @@ -923,7 +926,7 @@ public class Runtime { * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream) * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream) */ - @Deprecated + @Deprecated(since="1.1", forRemoval=true) public OutputStream getLocalizedOutputStream(OutputStream out) { return out; } diff --git a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java index 8ea8f09d103..e88a5eaa181 100644 --- a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java +++ b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java @@ -229,7 +229,7 @@ class SecurityManager { * It is recommended that the checkPermission * call be used instead. */ - @Deprecated + @Deprecated(since="1.2") protected boolean inCheck; /* @@ -262,7 +262,7 @@ class SecurityManager { * It is recommended that the checkPermission * call be used instead. */ - @Deprecated + @Deprecated(since="1.2") public boolean getInCheck() { return inCheck; } @@ -345,7 +345,7 @@ class SecurityManager { * @see java.lang.ClassLoader#getSystemClassLoader() getSystemClassLoader * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.2") protected ClassLoader currentClassLoader() { ClassLoader cl = currentClassLoader0(); if ((cl != null) && hasAllPermission()) @@ -391,7 +391,7 @@ class SecurityManager { * @see java.lang.ClassLoader#getSystemClassLoader() getSystemClassLoader * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.2") protected Class currentLoadedClass() { Class c = currentLoadedClass0(); if ((c != null) && hasAllPermission()) @@ -411,7 +411,7 @@ class SecurityManager { * call be used instead. * */ - @Deprecated + @Deprecated(since="1.2") protected native int classDepth(String name); /** @@ -449,7 +449,7 @@ class SecurityManager { * @see java.lang.ClassLoader#getSystemClassLoader() getSystemClassLoader * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.2") protected int classLoaderDepth() { int depth = classLoaderDepth0(); if (depth != -1) { @@ -474,7 +474,7 @@ class SecurityManager { * It is recommended that the checkPermission * call be used instead. */ - @Deprecated + @Deprecated(since="1.2") protected boolean inClass(String name) { return classDepth(name) >= 0; } @@ -491,7 +491,7 @@ class SecurityManager { * call be used instead. * @see #currentClassLoader() currentClassLoader */ - @Deprecated + @Deprecated(since="1.2") protected boolean inClassLoader() { return currentClassLoader() != null; } @@ -1217,7 +1217,7 @@ class SecurityManager { * @deprecated Use #checkPermission(java.security.Permission) instead * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.4") public void checkMulticast(InetAddress maddr, byte ttl) { String host = maddr.getHostAddress(); if (!host.startsWith("[") && host.indexOf(':') != -1) { @@ -1297,9 +1297,10 @@ class SecurityManager { * was trusted to bring up a top-level window. The method has been * obsoleted and code should instead use {@link #checkPermission} * to check {@code AWTPermission("showWindowWithoutWarningBanner")}. + * This method is subject to removal in a future version of Java SE. * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.8", forRemoval=true) public boolean checkTopLevelWindow(Object window) { if (window == null) { throw new NullPointerException("window can't be null"); @@ -1340,9 +1341,10 @@ class SecurityManager { * thread could access the system clipboard. The method has been * obsoleted and code should instead use {@link #checkPermission} * to check {@code AWTPermission("accessClipboard")}. + * This method is subject to removal in a future version of Java SE. * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.8", forRemoval=true) public void checkSystemClipboardAccess() { checkPermission(SecurityConstants.ALL_PERMISSION); } @@ -1358,9 +1360,10 @@ class SecurityManager { * thread could access the AWT event queue. The method has been * obsoleted and code should instead use {@link #checkPermission} * to check {@code AWTPermission("accessEventQueue")}. + * This method is subject to removal in a future version of Java SE. * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.8", forRemoval=true) public void checkAwtEventQueueAccess() { checkPermission(SecurityConstants.ALL_PERMISSION); } @@ -1626,12 +1629,13 @@ class SecurityManager { * Users of this method should instead invoke {@link #checkPermission} * directly. This method will be changed in a future release * to check the permission {@code java.security.AllPermission}. + * This method is subject to removal in a future version of Java SE. * * @see java.lang.reflect.Member * @since 1.1 * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.8", forRemoval=true) @CallerSensitive public void checkMemberAccess(Class clazz, int which) { if (clazz == null) { diff --git a/jdk/src/java.base/share/classes/java/lang/Short.java b/jdk/src/java.base/share/classes/java/lang/Short.java index 9fa79f3d8c2..57b291fc03a 100644 --- a/jdk/src/java.base/share/classes/java/lang/Short.java +++ b/jdk/src/java.base/share/classes/java/lang/Short.java @@ -302,7 +302,13 @@ public final class Short extends Number implements Comparable { * * @param value the value to be represented by the * {@code Short}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(short)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Short(short value) { this.value = value; } @@ -318,8 +324,14 @@ public final class Short extends Number implements Comparable { * {@code Short} * @throws NumberFormatException If the {@code String} * does not contain a parsable {@code short}. - * @see java.lang.Short#parseShort(java.lang.String, int) + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseShort(String)} to convert a string to a + * {@code short} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Short} object. */ + @Deprecated(since="9") public Short(String s) throws NumberFormatException { this.value = parseShort(s, 10); } diff --git a/jdk/src/java.base/share/classes/java/lang/String.java b/jdk/src/java.base/share/classes/java/lang/String.java index a609223d42f..a1772977727 100644 --- a/jdk/src/java.base/share/classes/java/lang/String.java +++ b/jdk/src/java.base/share/classes/java/lang/String.java @@ -363,7 +363,7 @@ public final class String * @see #String(byte[], java.nio.charset.Charset) * @see #String(byte[]) */ - @Deprecated + @Deprecated(since="1.1") public String(byte ascii[], int hibyte, int offset, int count) { checkBoundsOffCount(offset, count, ascii.length); if (count == 0) { @@ -415,7 +415,7 @@ public final class String * @see #String(byte[], java.nio.charset.Charset) * @see #String(byte[]) */ - @Deprecated + @Deprecated(since="1.1") public String(byte ascii[], int hibyte) { this(ascii, hibyte, 0, ascii.length); } @@ -911,7 +911,7 @@ public final class String * dst.length} * */ - @Deprecated + @Deprecated(since="1.1") public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) { checkBoundsBeginEnd(srcBegin, srcEnd, length()); Objects.requireNonNull(dst); diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java index 02975912bc0..2ddd37f5da1 100644 --- a/jdk/src/java.base/share/classes/java/lang/System.java +++ b/jdk/src/java.base/share/classes/java/lang/System.java @@ -1715,6 +1715,7 @@ public final class System { * finalizers being called on live objects while other threads are * concurrently manipulating those objects, resulting in erratic * behavior or deadlock. + * This method is subject to removal in a future version of Java SE. * @param value indicating enabling or disabling of finalization * @throws SecurityException * if a security manager exists and its checkExit @@ -1725,7 +1726,7 @@ public final class System { * @see java.lang.SecurityManager#checkExit(int) * @since 1.1 */ - @Deprecated + @Deprecated(since="1.2", forRemoval=true) public static void runFinalizersOnExit(boolean value) { Runtime.runFinalizersOnExit(value); } diff --git a/jdk/src/java.base/share/classes/java/lang/Thread.java b/jdk/src/java.base/share/classes/java/lang/Thread.java index 9c275ac1be9..040e1e98e5c 100644 --- a/jdk/src/java.base/share/classes/java/lang/Thread.java +++ b/jdk/src/java.base/share/classes/java/lang/Thread.java @@ -890,7 +890,7 @@ class Thread implements Runnable { * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. */ - @Deprecated + @Deprecated(since="1.2") public final void stop() { SecurityManager security = System.getSecurityManager(); if (security != null) { @@ -922,8 +922,9 @@ class Thread implements Runnable { * For more information, see * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. + * This method is subject to removal in a future version of Java SE. */ - @Deprecated + @Deprecated(since="1.2", forRemoval=true) public final synchronized void stop(Throwable obj) { throw new UnsupportedOperationException(); } @@ -1043,9 +1044,10 @@ class Thread implements Runnable { * "frozen" processes. For more information, see * * Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?. + * This method is subject to removal in a future version of Java SE. * @throws NoSuchMethodError always */ - @Deprecated + @Deprecated(since="1.5", forRemoval=true) public void destroy() { throw new NoSuchMethodError(); } @@ -1083,7 +1085,7 @@ class Thread implements Runnable { * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. */ - @Deprecated + @Deprecated(since="1.2") public final void suspend() { checkAccess(); suspend0(); @@ -1109,7 +1111,7 @@ class Thread implements Runnable { * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. */ - @Deprecated + @Deprecated(since="1.2") public final void resume() { checkAccess(); resume0(); @@ -1270,8 +1272,10 @@ class Thread implements Runnable { * @deprecated The definition of this call depends on {@link #suspend}, * which is deprecated. Further, the results of this call * were never well-defined. + * This method is subject to removal in a future version of Java SE. + * @see StackWalker */ - @Deprecated + @Deprecated(since="1.2", forRemoval=true) public native int countStackFrames(); /** diff --git a/jdk/src/java.base/share/classes/java/lang/ThreadGroup.java b/jdk/src/java.base/share/classes/java/lang/ThreadGroup.java index e477800f61c..0a97e4cad94 100644 --- a/jdk/src/java.base/share/classes/java/lang/ThreadGroup.java +++ b/jdk/src/java.base/share/classes/java/lang/ThreadGroup.java @@ -607,7 +607,7 @@ class ThreadGroup implements Thread.UncaughtExceptionHandler { * @deprecated This method is inherently unsafe. See * {@link Thread#stop} for details. */ - @Deprecated + @Deprecated(since="1.2") public final void stop() { if (stopOrSuspend(false)) Thread.currentThread().stop(); @@ -669,7 +669,7 @@ class ThreadGroup implements Thread.UncaughtExceptionHandler { * @deprecated This method is inherently deadlock-prone. See * {@link Thread#suspend} for details. */ - @Deprecated + @Deprecated(since="1.2") @SuppressWarnings("deprecation") public final void suspend() { if (stopOrSuspend(true)) @@ -732,7 +732,7 @@ class ThreadGroup implements Thread.UncaughtExceptionHandler { * both of which have been deprecated, as they are inherently * deadlock-prone. See {@link Thread#suspend} for details. */ - @Deprecated + @Deprecated(since="1.2") @SuppressWarnings("deprecation") public final void resume() { int ngroupsSnapshot; @@ -1073,7 +1073,7 @@ class ThreadGroup implements Thread.UncaughtExceptionHandler { * which is deprecated. Further, the behavior of this call * was never specified. */ - @Deprecated + @Deprecated(since="1.2") public boolean allowThreadSuspension(boolean b) { this.vmAllowSuspension = b; if (!b) { diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java index c2e68753e7b..993faf3fc0d 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -733,6 +733,7 @@ import java.util.Objects; } @Override + @SuppressWarnings("deprecation") public int hashCode() { // Avoid autoboxing getReferenceKind(), since this is used early and will force // early initialization of Byte$ByteCache diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/jdk/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java index 12e1723e0df..cc8dbbfffab 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java @@ -1750,7 +1750,7 @@ class ProxyGenerator { * Get or assign the index for a CONSTANT_Float entry. */ public short getFloat(float f) { - return getValue(new Float(f)); + return getValue(f); } /** diff --git a/jdk/src/java.base/share/classes/java/text/ChoiceFormat.java b/jdk/src/java.base/share/classes/java/text/ChoiceFormat.java index 8355dee87d4..98c66365c1b 100644 --- a/jdk/src/java.base/share/classes/java/text/ChoiceFormat.java +++ b/jdk/src/java.base/share/classes/java/text/ChoiceFormat.java @@ -437,7 +437,7 @@ public class ChoiceFormat extends NumberFormat { if (status.index == start) { status.errorIndex = furthest; } - return new Double(bestNumber); + return Double.valueOf(bestNumber); } /** diff --git a/jdk/src/java.base/share/classes/java/text/DecimalFormat.java b/jdk/src/java.base/share/classes/java/text/DecimalFormat.java index a82011fd7d5..587a64e13f1 100644 --- a/jdk/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/jdk/src/java.base/share/classes/java/text/DecimalFormat.java @@ -1996,7 +1996,7 @@ public class DecimalFormat extends NumberFormat { // special case NaN if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) { pos.index = pos.index + symbols.getNaN().length(); - return new Double(Double.NaN); + return Double.valueOf(Double.NaN); } boolean[] status = new boolean[STATUS_LENGTH]; @@ -2007,19 +2007,19 @@ public class DecimalFormat extends NumberFormat { // special case INFINITY if (status[STATUS_INFINITE]) { if (status[STATUS_POSITIVE] == (multiplier >= 0)) { - return new Double(Double.POSITIVE_INFINITY); + return Double.valueOf(Double.POSITIVE_INFINITY); } else { - return new Double(Double.NEGATIVE_INFINITY); + return Double.valueOf(Double.NEGATIVE_INFINITY); } } if (multiplier == 0) { if (digitList.isZero()) { - return new Double(Double.NaN); + return Double.valueOf(Double.NaN); } else if (status[STATUS_POSITIVE]) { - return new Double(Double.POSITIVE_INFINITY); + return Double.valueOf(Double.POSITIVE_INFINITY); } else { - return new Double(Double.NEGATIVE_INFINITY); + return Double.valueOf(Double.NEGATIVE_INFINITY); } } @@ -2093,8 +2093,8 @@ public class DecimalFormat extends NumberFormat { !isParseIntegerOnly(); } - return gotDouble ? - (Number)new Double(doubleResult) : (Number)Long.valueOf(longResult); + // cast inside of ?: because of binary numeric promotion, JLS 15.25 + return gotDouble ? (Number)doubleResult : (Number)longResult; } } diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java index 69ecc46cf6d..2af74b20961 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -455,7 +455,7 @@ public class ThreadLocalRandom extends Random { s = v1 * v1 + v2 * v2; } while (s >= 1 || s == 0); double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s); - nextLocalGaussian.set(new Double(v2 * multiplier)); + nextLocalGaussian.set(Double.valueOf(v2 * multiplier)); return v1 * multiplier; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java index d40facdafa4..e6a7cded42f 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java @@ -70,6 +70,7 @@ package jdk.internal.org.objectweb.asm; * @author Eric Bruneton * @author Eugene Kuleshov */ +@SuppressWarnings("deprecation") // for Integer(int) constructor public interface Opcodes { // ASM API versions @@ -176,6 +177,8 @@ public interface Opcodes { */ int F_SAME1 = 4; + // For reference comparison purposes, construct new instances + // instead of using valueOf() or autoboxing. Integer TOP = new Integer(0); Integer INTEGER = new Integer(1); Integer FLOAT = new Integer(2); diff --git a/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java b/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java index 2bb712e7867..8e52936ccb0 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java +++ b/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java @@ -168,7 +168,7 @@ class InheritedChannel { Class paramTypes[] = { int.class }; Constructor ctr = Reflect.lookupConstructor("java.io.FileDescriptor", paramTypes); - Object args[] = { new Integer(fdVal) }; + Object args[] = { Integer.valueOf(fdVal) }; FileDescriptor fd = (FileDescriptor)Reflect.invoke(ctr, args); diff --git a/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java b/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java index 8f464ddfd07..294cd5985bf 100644 --- a/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java +++ b/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java @@ -220,7 +220,7 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl case IP_TOS : case SO_RCVBUF : case SO_SNDBUF : - returnValue = new Integer(value); + returnValue = Integer.valueOf(value); break; default: /* shouldn't get here */ throw new SocketException("Option not supported"); diff --git a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java index cb74298d3dc..8e01c9e7332 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java +++ b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java @@ -87,13 +87,13 @@ final class WindowsSelectorImpl extends SelectorImpl { private static final class FdMap extends HashMap { static final long serialVersionUID = 0L; private MapEntry get(int desc) { - return get(new Integer(desc)); + return get(Integer.valueOf(desc)); } private MapEntry put(SelectionKeyImpl ski) { - return put(new Integer(ski.channel.getFDVal()), new MapEntry(ski)); + return put(Integer.valueOf(ski.channel.getFDVal()), new MapEntry(ski)); } private MapEntry remove(SelectionKeyImpl ski) { - Integer fd = new Integer(ski.channel.getFDVal()); + Integer fd = Integer.valueOf(ski.channel.getFDVal()); MapEntry x = get(fd); if ((x != null) && (x.ski.channel == ski.channel)) return remove(fd); diff --git a/jdk/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java b/jdk/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java index c32e9d0eea4..a1abeac9763 100644 --- a/jdk/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java +++ b/jdk/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java @@ -134,7 +134,7 @@ public class Klist { Character arg; for (int i = 0; i < args.length; i++) { if ((args[i].length() >= 2) && (args[i].startsWith("-"))) { - arg = new Character(args[i].charAt(1)); + arg = Character.valueOf(args[i].charAt(1)); switch (arg.charValue()) { case 'c': action = 'c'; diff --git a/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java b/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java index b17cd507e9e..55179670edb 100644 --- a/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java +++ b/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java @@ -1963,7 +1963,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern return (float)0; } try { - return ((new Float(value.toString())).floatValue()); + return Float.parseFloat(value.toString()); } catch (NumberFormatException ex) { throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.floatfail").toString(), new Object[] {value.toString().trim(), columnIndex})); @@ -2007,7 +2007,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern return (double)0; } try { - return ((new Double(value.toString().trim())).doubleValue()); + return Double.parseDouble(value.toString().trim()); } catch (NumberFormatException ex) { throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.doublefail").toString(), new Object[] {value.toString().trim(), columnIndex})); @@ -4017,9 +4017,9 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern return new BigDecimal(srcObj.toString().trim()); case java.sql.Types.REAL: case java.sql.Types.FLOAT: - return new Float(srcObj.toString().trim()); + return Float.valueOf(srcObj.toString().trim()); case java.sql.Types.DOUBLE: - return new Double(srcObj.toString().trim()); + return Double.valueOf(srcObj.toString().trim()); case java.sql.Types.CHAR: case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionExecuter.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionExecuter.java index a9aece44e30..c49cdf55502 100644 --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionExecuter.java +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionExecuter.java @@ -83,14 +83,14 @@ public class ExpressionExecuter implements ExpressionEvaluator { if (op == null) { return evaluate(l); } else { - Double lval = new Double(((Number)evaluate(l)).doubleValue()); - Double rval = new Double(((Number)evaluate(r)).doubleValue()); - double result = op.eval(lval.doubleValue(), rval.doubleValue()); + double lval = ((Number)evaluate(l)).doubleValue(); + double rval = ((Number)evaluate(r)).doubleValue(); + double result = op.eval(lval, rval); if (debug) { System.out.println("Performed Operation: " + lval + op + rval + " = " + result); } - return new Double(result); + return Double.valueOf(result); } } } diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java index c0e198438c6..63505988b8e 100644 --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java @@ -71,7 +71,7 @@ public class ExpressionResolver implements ExpressionEvaluator { if (m == null) { System.err.println("Warning: Unresolved Symbol: " + id.getName() + " substituted NaN"); - return new Literal(new Double(Double.NaN)); + return new Literal(Double.valueOf(Double.NaN)); } if (m.getVariability() == Variability.CONSTANT) { if (debug) { @@ -105,7 +105,7 @@ public class ExpressionResolver implements ExpressionEvaluator { Literal rl = (Literal)r; boolean warn = false; - Double nan = new Double(Double.NaN); + Double nan = Double.valueOf(Double.NaN); if (ll.getValue() instanceof String) { warn = true; ll.setValue(nan); } @@ -129,7 +129,7 @@ public class ExpressionResolver implements ExpressionEvaluator { + " (right = " + rn.doubleValue() + ")" + " to literal value " + result); } - return new Literal(new Double(result)); + return new Literal(Double.valueOf(result)); } } diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java index 33b17b95323..a9f9b203e20 100644 --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java @@ -324,7 +324,7 @@ public class Parser { case StreamTokenizer.TT_NUMBER: double literal = lookahead.nval; matchNumber(); - e = new Literal(new Double(literal)); + e = new Literal(Double.valueOf(literal)); log(pdebug, "Parsed: number -> " + literal); break; default: @@ -360,7 +360,7 @@ public class Parser { e1.setOperator(op); e1.setRight(e); log(pdebug, "Parsed: unary -> " + e1); - e1.setLeft(new Literal(new Double(0))); + e1.setLeft(new Literal(Double.valueOf(0))); e = e1; } } diff --git a/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java b/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java index 61823822d0e..bbae8bc44c8 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java @@ -478,7 +478,7 @@ class Commands { ThreadGroupReference tg = it.nextThreadGroup(); ++cnt; MessageOutput.println("thread group number description name", - new Object [] { new Integer (cnt), + new Object [] { Integer.valueOf(cnt), Env.description(tg), tg.name()}); } @@ -1014,7 +1014,7 @@ class Commands { return MessageOutput.format("locationString", new Object [] {loc.declaringType().name(), loc.method().name(), - new Integer (loc.lineNumber()), + Integer.valueOf(loc.lineNumber()), Long.valueOf(loc.codeIndex())}); } @@ -1467,7 +1467,7 @@ class Commands { MessageOutput.println("Line number information not available for"); } else if (Env.sourceLine(loc, lineno) == null) { MessageOutput.println("is an invalid line number for", - new Object [] {new Integer (lineno), + new Object [] {Integer.valueOf(lineno), refType.name()}); } else { for (int i = startLine; i <= endLine; i++) { @@ -1477,11 +1477,11 @@ class Commands { } if (i == lineno) { MessageOutput.println("source line number current line and line", - new Object [] {new Integer (i), + new Object [] {Integer.valueOf(i), sourceLine}); } else { MessageOutput.println("source line number and line", - new Object [] {new Integer (i), + new Object [] {Integer.valueOf(i), sourceLine}); } } @@ -1725,7 +1725,7 @@ class Commands { } else { MessageOutput.println("Owned by:", new Object [] {owner.name(), - new Integer (object.entryCount())}); + Integer.valueOf(object.entryCount())}); } List waiters = object.waitingThreads(); if (waiters.size() == 0) { diff --git a/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/MessageOutput.java b/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/MessageOutput.java index 8de0675183c..ac3decf432a 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/MessageOutput.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/MessageOutput.java @@ -198,7 +198,7 @@ public class MessageOutput { (MessageOutput.format("jdb prompt thread name and current stack frame", new Object [] { threadInfo.getThread().name(), - new Integer (threadInfo.getCurrentFrameIndex() + 1)})); + Integer.valueOf(threadInfo.getCurrentFrameIndex() + 1)})); } System.out.flush(); } From 6f26ab8d1258ae7752dfc866f35371f93253a181 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Mon, 18 Apr 2016 22:12:52 -0700 Subject: [PATCH 099/222] 8154498: fix to 8154403 results in failure of UserModuleTest.java on all platforms Reviewed-by: darcy, sundar --- .../plugins/InstalledModuleDescriptors/src/m1/p1/Main.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java index 4e516970d4d..915416c0802 100644 --- a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java @@ -29,6 +29,7 @@ import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.Set; public class Main { @@ -40,7 +41,8 @@ public class Main { validate(Main.class.getModule().getDescriptor()); // read m1/module-info.class - FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), null); + FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), + Collections.emptyMap()); Path path = fs.getPath("/", "modules", "m1", "module-info.class"); validate(ModuleDescriptor.read(Files.newInputStream(path))); } From 2ea14c96f7523f91f80c3aadbb5e18b0c8ad02c8 Mon Sep 17 00:00:00 2001 From: Felix Yang Date: Tue, 19 Apr 2016 01:40:13 -0700 Subject: [PATCH 100/222] 8146758: NetworkInterfaceStreamTest.java fails intermittently at comparing network interfaces Reviewed-by: chegar --- .../NetworkInterface/NetworkInterfaceStreamTest.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java index 7d8646d5361..08075ac7472 100644 --- a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java +++ b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java @@ -28,7 +28,6 @@ * @build java.base/java.util.stream.OpTestCase * @run testng/othervm NetworkInterfaceStreamTest * @run testng/othervm -Djava.net.preferIPv4Stack=true NetworkInterfaceStreamTest - * @key intermittent */ import org.testng.annotations.Test; @@ -52,21 +51,26 @@ public class NetworkInterfaceStreamTest extends OpTestCase { public void testNetworkInterfaces() throws SocketException { Supplier> ss = () -> { try { - return NetworkInterface.networkInterfaces(); + return allNetworkInterfaces(); } catch (SocketException e) { throw new RuntimeException(e); } }; - Collection expected = Collections.list(NetworkInterface.getNetworkInterfaces()); + Collection enums = Collections.list(NetworkInterface.getNetworkInterfaces()); + Collection expected = new ArrayList<>(); + enums.forEach(ni -> { + if (isIncluded(ni)) { + expected.add(ni); + } + }); withData(TestData.Factory.ofSupplier("Top-level network interfaces", ss)) .stream(s -> s) .expectedResult(expected) .exercise(); } - private Collection getAllNetworkInterfaces() throws SocketException { Collection anis = new ArrayList<>(); for (NetworkInterface ni : Collections.list(NetworkInterface.getNetworkInterfaces())) { From 2e3fd9639634142ab397b5e25f01050f6258e55a Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Tue, 19 Apr 2016 12:20:26 +0100 Subject: [PATCH 101/222] 8154487: java.httpclient/sun.net.httpclient.hpack.DecoderTest failing on Windows Reviewed-by: chegar --- .../share/classes/sun/net/httpclient/hpack/HeaderTable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java index 89820741a32..ab824a3df88 100644 --- a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java @@ -269,7 +269,7 @@ final class HeaderTable { StringBuilder b = new StringBuilder(); for (int i = 1, size = dynamicTable.size(); i <= size; i++) { HeaderField e = dynamicTable.get(i); - b.append(format("[%3d] (s = %3d) %s: %s%n", i, + b.append(format("[%3d] (s = %3d) %s: %s\n", i, sizeOf(e), e.name, e.value)); } b.append(format(" Table size:%4s", this.size)); From 402c448d0ac6ad2c3a8ce2fbd56d394f699de951 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Tue, 19 Apr 2016 14:39:35 +0200 Subject: [PATCH 102/222] 8150956: j.l.i.MethodHandles.whileLoop(...) and .iteratedLoop(...) throw unexpected exceptions in the case of 'init' return type is void Reviewed-by: psandoz --- .../java/lang/invoke/MethodHandles.java | 41 +++++++---- .../java/lang/invoke/LoopCombinatorTest.java | 70 ++++++++++++++++++- 2 files changed, 95 insertions(+), 16 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index ea688b14815..5f9fc90b54d 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -28,6 +28,7 @@ package java.lang.invoke; import java.lang.reflect.*; import java.util.ArrayList; import java.util.BitSet; +import java.util.Iterator; import java.util.List; import java.util.Arrays; import java.util.Objects; @@ -53,6 +54,7 @@ import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Opcodes; import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; +import static java.lang.invoke.MethodType.methodType; /** * This class consists exclusively of static methods that operate on or return @@ -3000,7 +3002,7 @@ assert((int)twice.invokeExact(21) == 42); private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length]; private static MethodHandle makeIdentity(Class ptype) { - MethodType mtype = MethodType.methodType(ptype, ptype); + MethodType mtype = methodType(ptype, ptype); LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype)); return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY); } @@ -3018,7 +3020,7 @@ assert((int)twice.invokeExact(21) == 42); } private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.values().length]; private static MethodHandle makeZero(Class rtype) { - MethodType mtype = MethodType.methodType(rtype); + MethodType mtype = methodType(rtype); LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype)); return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO); } @@ -3929,7 +3931,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); MethodHandle throwException(Class returnType, Class exType) { if (!Throwable.class.isAssignableFrom(exType)) throw new ClassCastException(exType.getName()); - return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType)); + return MethodHandleImpl.throwException(methodType(returnType, exType)); } /** @@ -4166,7 +4168,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); for (int i = 0; i < nclauses; ++i) { Class t = iterationVariableTypes.get(i); if (init.get(i) == null) { - init.set(i, empty(MethodType.methodType(t, commonSuffix))); + init.set(i, empty(methodType(t, commonSuffix))); } if (step.get(i) == null) { step.set(i, dropArgumentsToMatch(identityOrVoid(t), 0, commonParameterSequence, i)); @@ -4175,7 +4177,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); pred.set(i, dropArguments(constant(boolean.class, true), 0, commonParameterSequence)); } if (fini.get(i) == null) { - fini.set(i, empty(MethodType.methodType(t, commonParameterSequence))); + fini.set(i, empty(methodType(t, commonParameterSequence))); } } @@ -4269,7 +4271,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) { - MethodHandle fin = init == null ? zero(void.class) : identity(init.type().returnType()); + MethodHandle fin = init == null || init.type().returnType() == void.class ? zero(void.class) : + identity(init.type().returnType()); MethodHandle[] checkExit = {null, null, pred, fin}; MethodHandle[] varBody = {init, body}; return loop(checkExit, varBody); @@ -4335,7 +4338,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) { - MethodHandle fin = init == null ? zero(void.class) : identity(init.type().returnType()); + MethodHandle fin = init == null || init.type().returnType() == void.class ? zero(void.class) : + identity(init.type().returnType()); MethodHandle[] clause = {init, body, pred, fin}; return loop(clause); } @@ -4472,8 +4476,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) { - MethodHandle returnVar = dropArguments(init == null ? zero(void.class) : identity(init.type().returnType()), - 0, int.class, int.class); + MethodHandle returnVar = dropArguments(init == null || init.type().returnType() == void.class ? + zero(void.class) : identity(init.type().returnType()), 0, int.class, int.class); MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)}; MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar}; MethodHandle[] bodyClause = {init, @@ -4485,6 +4489,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); /** * Constructs a loop that ranges over the elements produced by an {@code Iterator}. * The iterator will be produced by the evaluation of the {@code iterator} handle. + * This handle must have {@link java.util.Iterator} as its return type. * If this handle is passed as {@code null} the method {@link Iterable#iterator} will be used instead, * and will be applied to a leading argument of the loop handle. * Each value produced by the iterator is passed to the {@code body}, which must accept an initial {@code T} parameter. @@ -4534,7 +4539,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * assertEquals(reversedList, (List) loop.invoke(list)); * } *

    - * @implSpec The implementation of this method is equivalent to: + * @implSpec The implementation of this method is equivalent to (excluding error handling): *

    {@code
          * MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
          *     // assume MH_next and MH_hasNext are handles to methods of Iterator
    @@ -4550,6 +4555,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
          * }
    * * @param iterator a handle to return the iterator to start the loop. + * The handle must have {@link java.util.Iterator} as its return type. * Passing {@code null} will make the loop call {@link Iterable#iterator()} on the first * incoming value. * @param init initializer for additional loop state. This determines the loop's result type. @@ -4565,21 +4571,23 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) { - checkIteratedLoop(body); + checkIteratedLoop(iterator, body); + final boolean voidInit = init == null || init.type().returnType() == void.class; MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator); MethodHandle initIterator = iterator == null ? - initit.asType(initit.type().changeParameterType(0, body.type().parameterType(init == null ? 1 : 2))) : + initit.asType(initit.type().changeParameterType(0, body.type().parameterType(voidInit ? 1 : 2))) : iterator; Class itype = initIterator.type().returnType(); Class ttype = body.type().parameterType(0); MethodHandle returnVar = - dropArguments(init == null ? zero(void.class) : identity(init.type().returnType()), 0, itype); + dropArguments(voidInit ? zero(void.class) : identity(init.type().returnType()), 0, itype); MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext); MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype)); - MethodHandle[] iterVar = {initIterator, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred), returnVar}; + MethodHandle[] iterVar = {initIterator, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred), + returnVar}; MethodHandle[] bodyClause = {init, filterArgument(body, 0, nextVal)}; return loop(iterVar, bodyClause); @@ -4833,7 +4841,10 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); } } - private static void checkIteratedLoop(MethodHandle body) { + private static void checkIteratedLoop(MethodHandle iterator, MethodHandle body) { + if (null != iterator && !Iterator.class.isAssignableFrom(iterator.type().returnType())) { + throw newIllegalArgumentException("iteratedLoop first argument must have Iterator return type"); + } if (null == body) { throw newIllegalArgumentException("iterated loop body must not be null"); } diff --git a/jdk/test/java/lang/invoke/LoopCombinatorTest.java b/jdk/test/java/lang/invoke/LoopCombinatorTest.java index 71e4b0e89d8..1df672fb997 100644 --- a/jdk/test/java/lang/invoke/LoopCombinatorTest.java +++ b/jdk/test/java/lang/invoke/LoopCombinatorTest.java @@ -26,6 +26,7 @@ /* @test * @bug 8139885 * @bug 8150635 + * @bug 8150956 * @bug 8150957 * @bug 8153637 * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest @@ -265,6 +266,28 @@ public class LoopCombinatorTest { assertEquals(v, w.i); } + @Test + public static void testWhileVoidInit() throws Throwable { + While w = new While(); + int v = 5; + MethodHandle loop = MethodHandles.whileLoop(While.MH_voidInit.bindTo(w), While.MH_voidPred.bindTo(w), + While.MH_voidBody.bindTo(w)); + assertEquals(While.MT_void, loop.type()); + loop.invoke(v); + assertEquals(v, w.i); + } + + @Test + public static void testDoWhileVoidInit() throws Throwable { + While w = new While(); + int v = 5; + MethodHandle loop = MethodHandles.doWhileLoop(While.MH_voidInit.bindTo(w), While.MH_voidBody.bindTo(w), + While.MH_voidPred.bindTo(w)); + assertEquals(While.MT_void, loop.type()); + loop.invoke(v); + assertEquals(v, w.i); + } + @Test public static void testCountedLoop() throws Throwable { // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s; => a variation on a well known theme @@ -274,6 +297,14 @@ public class LoopCombinatorTest { assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!")); } + @Test + public static void testCountedLoopVoidInit() throws Throwable { + MethodHandle fit5 = MethodHandles.constant(int.class, 5); + MethodHandle loop = MethodHandles.countedLoop(fit5, MethodHandles.zero(void.class), Counted.MH_printHello); + assertEquals(Counted.MT_countedPrinting, loop.type()); + loop.invoke(); + } + @Test public static void testCountedArrayLoop() throws Throwable { // int[] a = new int[]{0}; for (int i = 0; i < 13; ++i) { ++a[0]; } => a[0] == 13 @@ -360,7 +391,8 @@ public class LoopCombinatorTest { public static void testIterateNullBody() { boolean caught = false; try { - MethodHandles.iteratedLoop(MethodHandles.identity(int.class), MethodHandles.identity(int.class), null); + MethodHandles.iteratedLoop(MethodHandles.empty(methodType(Iterator.class, int.class)), + MethodHandles.identity(int.class), null); } catch (IllegalArgumentException iae) { assertEquals("iterated loop body must not be null", iae.getMessage()); caught = true; @@ -368,6 +400,26 @@ public class LoopCombinatorTest { assertTrue(caught); } + @Test + public static void testIterateVoidIterator() { + boolean caught = false; + MethodType v = methodType(void.class); + try { + MethodHandles.iteratedLoop(MethodHandles.empty(v), null, MethodHandles.empty(v)); + } catch(IllegalArgumentException iae) { + assertEquals("iteratedLoop first argument must have Iterator return type", iae.getMessage()); + caught = true; + } + assertTrue(caught); + } + + @Test + public static void testIterateVoidInit() throws Throwable { + MethodHandle loop = MethodHandles.iteratedLoop(null, Iterate.MH_voidInit, Iterate.MH_printStep); + assertEquals(Iterate.MT_print, loop.type()); + loop.invoke(Arrays.asList("hello", "world")); + } + static class Empty { static void f() { } @@ -604,6 +656,10 @@ public class LoopCombinatorTest { private int i = 0; + void voidInit(int k) { + // empty + } + void voidBody(int k) { ++i; } @@ -623,6 +679,7 @@ public class LoopCombinatorTest { static final MethodType MT_zipInitZip = methodType(List.class, Iterator.class, Iterator.class); static final MethodType MT_zipPred = methodType(boolean.class, List.class, Iterator.class, Iterator.class); static final MethodType MT_zipStep = methodType(List.class, List.class, Iterator.class, Iterator.class); + static final MethodType MT_voidInit = methodType(void.class, int.class); static final MethodType MT_voidBody = methodType(void.class, int.class); static final MethodType MT_voidPred = methodType(boolean.class, int.class); @@ -635,6 +692,7 @@ public class LoopCombinatorTest { static final MethodHandle MH_zipInitZip; static final MethodHandle MH_zipPred; static final MethodHandle MH_zipStep; + static final MethodHandle MH_voidInit; static final MethodHandle MH_voidBody; static final MethodHandle MH_voidPred; @@ -654,6 +712,7 @@ public class LoopCombinatorTest { MH_zipInitZip = LOOKUP.findStatic(WHILE, "zipInitZip", MT_zipInitZip); MH_zipPred = LOOKUP.findStatic(WHILE, "zipPred", MT_zipPred); MH_zipStep = LOOKUP.findStatic(WHILE, "zipStep", MT_zipStep); + MH_voidInit = LOOKUP.findVirtual(WHILE, "voidInit", MT_voidInit); MH_voidBody = LOOKUP.findVirtual(WHILE, "voidBody", MT_voidBody); MH_voidPred = LOOKUP.findVirtual(WHILE, "voidPred", MT_voidPred); } catch (Exception e) { @@ -768,6 +827,10 @@ public class LoopCombinatorTest { System.out.print(s); } + static void voidInit() { + // empty + } + static final Class ITERATE = Iterate.class; static final MethodType MT_sumIterator = methodType(Iterator.class, Integer[].class); @@ -783,6 +846,8 @@ public class LoopCombinatorTest { static final MethodType MT_mapStep = methodType(List.class, String.class, List.class, List.class); static final MethodType MT_printStep = methodType(void.class, String.class, List.class); + static final MethodType MT_voidInit = methodType(void.class); + static final MethodHandle MH_sumIterator; static final MethodHandle MH_sumInit; static final MethodHandle MH_sumStep; @@ -797,6 +862,8 @@ public class LoopCombinatorTest { static final MethodHandle MH_mapInit; static final MethodHandle MH_mapStep; + static final MethodHandle MH_voidInit; + static final MethodType MT_sum = methodType(int.class, Integer[].class); static final MethodType MT_reverse = methodType(List.class, List.class); static final MethodType MT_length = methodType(int.class, List.class); @@ -815,6 +882,7 @@ public class LoopCombinatorTest { MH_mapInit = LOOKUP.findStatic(ITERATE, "mapInit", MT_mapInit); MH_mapStep = LOOKUP.findStatic(ITERATE, "mapStep", MT_mapStep); MH_printStep = LOOKUP.findStatic(ITERATE, "printStep", MT_printStep); + MH_voidInit = LOOKUP.findStatic(ITERATE, "voidInit", MT_voidInit); } catch (Exception e) { throw new ExceptionInInitializerError(e); } From dc9721e592c013135b85736f3c026071def08d70 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Mon, 18 Apr 2016 09:38:38 -0700 Subject: [PATCH 103/222] 8154470: defines.h confused about PROGNAME and JAVA_ARGS Fiddle with const_progname initializations Reviewed-by: ksrini, alanb --- .../java.base/share/native/launcher/defines.h | 12 ++-- jdk/test/tools/launcher/Arrrghs.java | 4 +- .../tools/launcher/DefaultLocaleTestRun.java | 2 +- .../tools/launcher/ExecutionEnvironment.java | 14 ++-- jdk/test/tools/launcher/FXLauncherTest.java | 6 +- jdk/test/tools/launcher/I18NTest.java | 2 +- jdk/test/tools/launcher/MiscTests.java | 30 ++++---- jdk/test/tools/launcher/Settings.java | 71 +++++++++---------- jdk/test/tools/launcher/TestHelper.java | 12 ++-- jdk/test/tools/launcher/TestSpecialArgs.java | 2 +- .../tools/launcher/TooSmallStackSize.java | 7 +- jdk/test/tools/launcher/ToolsOpts.java | 2 +- jdk/test/tools/launcher/VersionCheck.java | 3 +- 13 files changed, 78 insertions(+), 89 deletions(-) diff --git a/jdk/src/java.base/share/native/launcher/defines.h b/jdk/src/java.base/share/native/launcher/defines.h index e3b18882df4..3b63e038f9d 100644 --- a/jdk/src/java.base/share/native/launcher/defines.h +++ b/jdk/src/java.base/share/native/launcher/defines.h @@ -45,7 +45,11 @@ #ifdef JAVA_ARGS #define HAS_JAVA_ARGS JNI_TRUE -static const char* const_progname = "java"; +#ifdef PROGNAME +static const char* const_progname = PROGNAME; +#else +static char* const_progname = NULL; +#endif static const char* const_jargs[] = JAVA_ARGS; /* * ApplicationHome is prepended to each of these entries; the resulting @@ -59,11 +63,7 @@ static const char* const_appclasspath[] = APP_CLASSPATH; #endif /* APP_CLASSPATH */ #else /* !JAVA_ARGS */ #define HAS_JAVA_ARGS JNI_FALSE -#ifdef PROGNAME -static const char* const_progname = PROGNAME; -#else -static char* const_progname = NULL; -#endif +static const char* const_progname = "java"; static const char** const_jargs = NULL; static const char* const_appclasspath[] = { NULL }; #endif /* JAVA_ARGS */ diff --git a/jdk/test/tools/launcher/Arrrghs.java b/jdk/test/tools/launcher/Arrrghs.java index cb36d2dfe8a..9045e010473 100644 --- a/jdk/test/tools/launcher/Arrrghs.java +++ b/jdk/test/tools/launcher/Arrrghs.java @@ -489,7 +489,7 @@ public class Arrrghs extends TestHelper { return; } - TestResult tr = null; + TestResult tr; // a missing class createJar("MIA", new File("some.jar"), new File("Foo"), @@ -592,7 +592,7 @@ public class Arrrghs extends TestHelper { if (!isEnglishLocale()) { // only english version return; } - TestResult tr = null; + TestResult tr; // a missing class createJar("MIA", new File("some.jar"), new File("Foo"), (String[])null); diff --git a/jdk/test/tools/launcher/DefaultLocaleTestRun.java b/jdk/test/tools/launcher/DefaultLocaleTestRun.java index c1183e78814..2d4091912e2 100644 --- a/jdk/test/tools/launcher/DefaultLocaleTestRun.java +++ b/jdk/test/tools/launcher/DefaultLocaleTestRun.java @@ -41,7 +41,7 @@ public class DefaultLocaleTestRun extends TestHelper { System.out.println("Test passes vacuously on non-windows"); return; } - TestResult tr = null; + TestResult tr; tr = doExec(javaCmd, "-cp", TEST_CLASSES_DIR.getAbsolutePath(), "DefaultLocaleTest", "-w", "x.out"); diff --git a/jdk/test/tools/launcher/ExecutionEnvironment.java b/jdk/test/tools/launcher/ExecutionEnvironment.java index 58acf380b0e..62903b33ecb 100644 --- a/jdk/test/tools/launcher/ExecutionEnvironment.java +++ b/jdk/test/tools/launcher/ExecutionEnvironment.java @@ -120,15 +120,14 @@ public class ExecutionEnvironment extends TestHelper { */ @Test void testEcoFriendly() { - TestResult tr = null; - Map env = new HashMap<>(); for (String x : LD_PATH_STRINGS) { String pairs[] = x.split("="); env.put(pairs[0], pairs[1]); } - tr = doExec(env, javaCmd, "-jar", testJarFile.getAbsolutePath()); + TestResult tr = + doExec(env, javaCmd, "-jar", testJarFile.getAbsolutePath()); if (!tr.isNotZeroOutput()) { flagError(tr, "Error: No output at all. Did the test execute ?"); @@ -180,7 +179,7 @@ public class ExecutionEnvironment extends TestHelper { */ @Test void testJavaLibraryPath() { - TestResult tr = null; + TestResult tr; Map env = new HashMap<>(); @@ -240,17 +239,14 @@ public class ExecutionEnvironment extends TestHelper { */ @Test void testVmSelection() { - - TestResult tr = null; - if (haveClientVM) { - tr = doExec(javaCmd, "-client", "-version"); + TestResult tr = doExec(javaCmd, "-client", "-version"); if (!tr.matches(".*Client VM.*")) { flagError(tr, "the expected vm -client did not launch"); } } if (haveServerVM) { - tr = doExec(javaCmd, "-server", "-version"); + TestResult tr = doExec(javaCmd, "-server", "-version"); if (!tr.matches(".*Server VM.*")) { flagError(tr, "the expected vm -server did not launch"); } diff --git a/jdk/test/tools/launcher/FXLauncherTest.java b/jdk/test/tools/launcher/FXLauncherTest.java index a885cb8dbf6..0ee9d981cda 100644 --- a/jdk/test/tools/launcher/FXLauncherTest.java +++ b/jdk/test/tools/launcher/FXLauncherTest.java @@ -239,7 +239,7 @@ public class FXLauncherTest extends TestHelper { createFile(ManifestFile, createManifestContents(StdMainClass, fxMC)); createJar(FXtestJar, ManifestFile); String sTestJar = FXtestJar.getAbsolutePath(); - TestResult tr; + final TestResult tr; if (useCP) { tr = doExec(javaCmd, "-cp", sTestJar, StdMainClass, APP_PARMS[0], APP_PARMS[1]); } else { @@ -290,7 +290,7 @@ public class FXLauncherTest extends TestHelper { createFile(ManifestFile, createManifestContents(ExtMainClass, fxMC)); createJar(FXtestJar, ManifestFile); String sTestJar = FXtestJar.getAbsolutePath(); - TestResult tr; + final TestResult tr; if (useCP) { tr = doExec(javaCmd, "-cp", sTestJar, ExtMainClass, APP_PARMS[0], APP_PARMS[1]); } else { @@ -359,7 +359,7 @@ public class FXLauncherTest extends TestHelper { createFile(ManifestFile, createManifestContents(NonFXMainClass, null)); createJar(FXtestJar, ManifestFile); String sTestJar = FXtestJar.getAbsolutePath(); - TestResult tr; + final TestResult tr; if (useCP) { tr = doExec(javaCmd, "-verbose:class", "-cp", sTestJar, NonFXMainClass, APP_PARMS[0], APP_PARMS[1]); diff --git a/jdk/test/tools/launcher/I18NTest.java b/jdk/test/tools/launcher/I18NTest.java index 3af5d593afc..aa1ce24e798 100644 --- a/jdk/test/tools/launcher/I18NTest.java +++ b/jdk/test/tools/launcher/I18NTest.java @@ -60,7 +60,7 @@ public class I18NTest extends TestHelper { // compile the generate code using the javac compiler vs. the api, to // as a bonus point to see if the argument is passed correctly - TestResult tr = null; + TestResult tr; tr = doExec(javacCmd, fileName + JAVA_FILE_EXT); if (!tr.isOK()) { System.out.println(tr); diff --git a/jdk/test/tools/launcher/MiscTests.java b/jdk/test/tools/launcher/MiscTests.java index 3769d117894..7b82abc4f48 100644 --- a/jdk/test/tools/launcher/MiscTests.java +++ b/jdk/test/tools/launcher/MiscTests.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6856415 8154212 + * @bug 6856415 8154212 8154470 * @summary Miscellaneous tests, Exceptions * @compile -XDignore.symbol.file MiscTests.java * @run main MiscTests @@ -95,30 +95,34 @@ public class MiscTests extends TestHelper { TestResult tr = doExec(javaCmd, "-Djava.security.manager", "-jar", testJar.getName(), "foo.bak"); - for (String s : tr.testOutput) { - System.out.println(s); - } if (!tr.contains("java.security.AccessControlException:" + " access denied (\"java.lang.RuntimePermission\"" + " \"accessClassInPackage.sun.security.pkcs11\")")) { - System.out.println(tr.status); + System.out.println(tr); } } - static void testJLDEnvWithTool() { - final Map envMap = new HashMap<>(); - envMap.put("_JAVA_LAUNCHER_DEBUG", "true"); - TestResult tr = doExec(envMap, javacCmd, "-version"); - tr.checkPositive(); - if (!tr.isOK()) { - System.out.println(tr); + static void testJLDEnv() { + final Map envToSet = new HashMap<>(); + envToSet.put("_JAVA_LAUNCHER_DEBUG", "true"); + for (String cmd : new String[] { javaCmd, javacCmd }) { + TestResult tr = doExec(envToSet, cmd, "-version"); + tr.checkPositive(); + String javargs = cmd.equals(javacCmd) ? "on" : "off"; + String progname = cmd.equals(javacCmd) ? "javac" : "java"; + if (!tr.isOK() + || !tr.matches("\\s*debug:on$") + || !tr.matches("\\s*javargs:" + javargs + "$") + || !tr.matches("\\s*program name:" + progname + "$")) { + System.out.println(tr); + } } } public static void main(String... args) throws IOException { testWithClassPathSetViaProperty(); test6856415(); - testJLDEnvWithTool(); + testJLDEnv(); if (testExitValue != 0) { throw new Error(testExitValue + " tests failed"); } diff --git a/jdk/test/tools/launcher/Settings.java b/jdk/test/tools/launcher/Settings.java index 8d45c8288b6..bd8f238108a 100644 --- a/jdk/test/tools/launcher/Settings.java +++ b/jdk/test/tools/launcher/Settings.java @@ -55,9 +55,9 @@ public class Settings extends TestHelper { } } - static void checkNoContains(TestResult tr, String str) { - if (tr.contains(str)) { - System.out.println(tr.status); + static void checkNotContains(TestResult tr, String str) { + if (!tr.notContains(str)) { + System.out.println(tr); throw new RuntimeException(str + " found"); } } @@ -77,84 +77,77 @@ public class Settings extends TestHelper { if (getArch().equals("ppc64") || getArch().equals("ppc64le")) { stackSize = "800"; } - TestResult tr = null; + TestResult tr; tr = doExec(javaCmd, "-Xms64m", "-Xmx512m", "-Xss" + stackSize + "k", "-XshowSettings", "-jar", testJar.getAbsolutePath()); containsAllOptions(tr); if (!tr.isOK()) { - System.out.println(tr.status); + System.out.println(tr); throw new RuntimeException("test fails"); } tr = doExec(javaCmd, "-Xms65536k", "-Xmx712m", "-Xss" + stackSize + "000", "-XshowSettings", "-jar", testJar.getAbsolutePath()); containsAllOptions(tr); if (!tr.isOK()) { - System.out.println(tr.status); + System.out.println(tr); throw new RuntimeException("test fails"); } } static void runTestOptionAll() throws IOException { init(); - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings:all"); + TestResult tr = doExec(javaCmd, "-XshowSettings:all"); containsAllOptions(tr); } static void runTestOptionVM() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings:vm"); + TestResult tr = doExec(javaCmd, "-XshowSettings:vm"); checkContains(tr, VM_SETTINGS); - checkNoContains(tr, PROP_SETTINGS); - checkNoContains(tr, LOCALE_SETTINGS); + checkNotContains(tr, PROP_SETTINGS); + checkNotContains(tr, LOCALE_SETTINGS); } static void runTestOptionProperty() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings:properties"); - checkNoContains(tr, VM_SETTINGS); + TestResult tr = doExec(javaCmd, "-XshowSettings:properties"); + checkNotContains(tr, VM_SETTINGS); checkContains(tr, PROP_SETTINGS); - checkNoContains(tr, LOCALE_SETTINGS); + checkNotContains(tr, LOCALE_SETTINGS); } static void runTestOptionLocale() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings:locale"); - checkNoContains(tr, VM_SETTINGS); - checkNoContains(tr, PROP_SETTINGS); + TestResult tr = doExec(javaCmd, "-XshowSettings:locale"); + checkNotContains(tr, VM_SETTINGS); + checkNotContains(tr, PROP_SETTINGS); checkContains(tr, LOCALE_SETTINGS); } static void runTestBadOptions() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettingsBadOption"); - checkNoContains(tr, VM_SETTINGS); - checkNoContains(tr, PROP_SETTINGS); - checkNoContains(tr, LOCALE_SETTINGS); + TestResult tr = doExec(javaCmd, "-XshowSettingsBadOption"); + checkNotContains(tr, VM_SETTINGS); + checkNotContains(tr, PROP_SETTINGS); + checkNotContains(tr, LOCALE_SETTINGS); checkContains(tr, "Unrecognized option: -XshowSettingsBadOption"); } static void runTest7123582() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings", "-version"); + TestResult tr = doExec(javaCmd, "-XshowSettings", "-version"); if (!tr.isOK()) { - System.out.println(tr.status); + System.out.println(tr); throw new RuntimeException("test fails"); } containsAllOptions(tr); } - public static void main(String... args) { - try { - runTestOptionAll(); - runTestOptionDefault(); - runTestOptionVM(); - runTestOptionProperty(); - runTestOptionLocale(); - runTestBadOptions(); - runTest7123582(); - } catch (IOException ioe) { - throw new RuntimeException(ioe); + public static void main(String... args) throws IOException { + runTestOptionAll(); + runTestOptionDefault(); + runTestOptionVM(); + runTestOptionProperty(); + runTestOptionLocale(); + runTestBadOptions(); + runTest7123582(); + if (testExitValue != 0) { + throw new Error(testExitValue + " tests failed"); } } } diff --git a/jdk/test/tools/launcher/TestHelper.java b/jdk/test/tools/launcher/TestHelper.java index 402102b2cd5..6724daf2396 100644 --- a/jdk/test/tools/launcher/TestHelper.java +++ b/jdk/test/tools/launcher/TestHelper.java @@ -603,23 +603,23 @@ public class TestHelper { return true; } - boolean matches(String stringToMatch) { + boolean matches(String regexToMatch) { for (String x : testOutput) { - if (x.matches(stringToMatch)) { + if (x.matches(regexToMatch)) { return true; } } - appendError("string <" + stringToMatch + "> not found"); + appendError("regex <" + regexToMatch + "> not matched"); return false; } - boolean notMatches(String stringToMatch) { + boolean notMatches(String regexToMatch) { for (String x : testOutput) { - if (!x.matches(stringToMatch)) { + if (!x.matches(regexToMatch)) { return true; } } - appendError("string <" + stringToMatch + "> found"); + appendError("regex <" + regexToMatch + "> matched"); return false; } } diff --git a/jdk/test/tools/launcher/TestSpecialArgs.java b/jdk/test/tools/launcher/TestSpecialArgs.java index 307a4e06fb4..0cb75908b8f 100644 --- a/jdk/test/tools/launcher/TestSpecialArgs.java +++ b/jdk/test/tools/launcher/TestSpecialArgs.java @@ -241,7 +241,7 @@ public class TestSpecialArgs extends TestHelper { @Test void testNMArgumentProcessing() throws FileNotFoundException { - TestResult tr = null; + TestResult tr; // the direct invokers of the VM String options[] = { "-version", "-fullversion", "-help", "-?", "-X" diff --git a/jdk/test/tools/launcher/TooSmallStackSize.java b/jdk/test/tools/launcher/TooSmallStackSize.java index dac1c7f0325..7cc02ab56df 100644 --- a/jdk/test/tools/launcher/TooSmallStackSize.java +++ b/jdk/test/tools/launcher/TooSmallStackSize.java @@ -85,11 +85,10 @@ public class TooSmallStackSize extends TestHelper { */ static String checkStack(String stackSize) { String min_stack_allowed; - TestResult tr; if (verbose) System.out.println("*** Testing " + stackSize); - tr = doExec(javaCmd, "-Xss" + stackSize, "-version"); + TestResult tr = doExec(javaCmd, "-Xss" + stackSize, "-version"); if (verbose) printTestOutput(tr); @@ -114,11 +113,9 @@ public class TooSmallStackSize extends TestHelper { * Run the JVM with the minimum allowed stack size. This should always succeed. */ static void checkMinStackAllowed(String stackSize) { - TestResult tr = null; - if (verbose) System.out.println("*** Testing " + stackSize); - tr = doExec(javaCmd, "-Xss" + stackSize, "-version"); + TestResult tr = doExec(javaCmd, "-Xss" + stackSize, "-version"); if (verbose) printTestOutput(tr); diff --git a/jdk/test/tools/launcher/ToolsOpts.java b/jdk/test/tools/launcher/ToolsOpts.java index bff769a54ff..a0f67d24203 100644 --- a/jdk/test/tools/launcher/ToolsOpts.java +++ b/jdk/test/tools/launcher/ToolsOpts.java @@ -149,7 +149,7 @@ public class ToolsOpts extends TestHelper { */ static void runTestOptions() throws IOException { init(); - TestResult tr = null; + TestResult tr; int jpos = -1; for (String arg[] : optionPatterns) { jpos = indexOfJoption(arg); diff --git a/jdk/test/tools/launcher/VersionCheck.java b/jdk/test/tools/launcher/VersionCheck.java index 08a18bd2a28..13dac4f01be 100644 --- a/jdk/test/tools/launcher/VersionCheck.java +++ b/jdk/test/tools/launcher/VersionCheck.java @@ -151,12 +151,11 @@ public class VersionCheck extends TestHelper { * of the -version output as they are inconsistent. */ static boolean testToolVersion() { - TestResult tr = null; TestHelper.testExitValue = 0; for (File f : new File(JAVA_BIN).listFiles(new ToolFilter(BLACKLIST_VERSION))) { String x = f.getAbsolutePath(); System.out.println("Testing (-version): " + x); - tr = doExec(x, "-version"); + TestResult tr = doExec(x, "-version"); tr.checkPositive(); } return TestHelper.testExitValue == 0; From 5acf187999317e172bc783dbb8ed6b87aaae1447 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Mon, 18 Apr 2016 14:11:16 -0700 Subject: [PATCH 104/222] 8145468: update java.lang APIs with new deprecations Reviewed-by: lancea, alanb --- make/CompileJavaModules.gmk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index c4275f863e3..4ce9cca25bf 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -98,7 +98,8 @@ java.datatransfer_COPY := flavormap.properties ################################################################################ -java.desktop_ADD_JAVAC_FLAGS := -Xdoclint:all/protected,-reference '-Xdoclint/package:java.*,javax.*' +java.desktop_ADD_JAVAC_FLAGS := -Xdoclint:all/protected,-reference \ + '-Xdoclint/package:java.*,javax.*' -Xlint:-deprecation java.desktop_COPY := .gif .png .wav .txt .xml .css .pf java.desktop_CLEAN := iio-plugin.properties cursors.properties From 108c188df5061703f06aab3b25637749a2583277 Mon Sep 17 00:00:00 2001 From: Ajit Ghaisas Date: Tue, 19 Apr 2016 13:00:00 +0530 Subject: [PATCH 105/222] 8031423: Test java/awt/dnd/DisposeFrameOnDragCrash/DisposeFrameOnDragTest.java fails by Timeout on Windows Reviewed-by: yan, arapte --- .../DisposeFrameOnDragTest.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/jdk/test/java/awt/dnd/DisposeFrameOnDragCrash/DisposeFrameOnDragTest.java b/jdk/test/java/awt/dnd/DisposeFrameOnDragCrash/DisposeFrameOnDragTest.java index 05cd0d51840..bfeb4bda85a 100644 --- a/jdk/test/java/awt/dnd/DisposeFrameOnDragCrash/DisposeFrameOnDragTest.java +++ b/jdk/test/java/awt/dnd/DisposeFrameOnDragCrash/DisposeFrameOnDragTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,17 +56,24 @@ public class DisposeFrameOnDragTest { } }); - Util.waitForIdle(null); + Robot testRobot = null; try { - Point loc = textArea.getLocationOnScreen(); - Util.drag(new Robot(), - new Point((int) loc.x + 3, (int) loc.y + 3), - new Point((int) loc.x + 40, (int) loc.y + 40), - InputEvent.BUTTON1_MASK); - } catch (AWTException ex) { - throw new RuntimeException("Could not initiate a drag operation"); + testRobot = new Robot(); + } catch(AWTException ex) { + throw new RuntimeException("Error while creating Robot"); } - Util.waitForIdle(null); + + Util.waitForIdle(testRobot); + + Point loc = textArea.getLocationOnScreen(); + Util.drag(testRobot, + new Point((int) loc.x + 3, (int) loc.y + 3), + new Point((int) loc.x + 40, (int) loc.y + 40), + InputEvent.BUTTON1_MASK); + + Util.waitForIdle(testRobot); + + testRobot.delay(200); } private static void constructTestUI() { From ebb86eaa4f6da5ab0985b8ad4c8981fa43c494eb Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Tue, 19 Apr 2016 14:34:43 +0100 Subject: [PATCH 106/222] 8148863: Remove sun.misc.ManagedLocalsThread from corba Reviewed-by: alanb, coffeys, msheppar --- .../classes/com/sun/corba/se/impl/corba/RequestImpl.java | 2 +- .../classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java | 3 ++- .../share/classes/com/sun/corba/se/impl/oa/poa/POAImpl.java | 3 ++- .../classes/com/sun/corba/se/impl/oa/poa/POAManagerImpl.java | 2 +- .../sun/corba/se/impl/oa/poa/POAPolicyMediatorImpl_R_USM.java | 3 ++- .../share/classes/com/sun/corba/se/impl/orb/ORBImpl.java | 2 +- .../sun/corba/se/impl/orbutil/threadpool/ThreadPoolImpl.java | 4 ++-- .../classes/com/sun/corba/se/impl/transport/SelectorImpl.java | 4 ++-- corba/src/java.corba/share/classes/module-info.java | 2 -- 9 files changed, 13 insertions(+), 12 deletions(-) diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/corba/RequestImpl.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/corba/RequestImpl.java index 3c357f61c38..69b58393d95 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/corba/RequestImpl.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/corba/RequestImpl.java @@ -255,7 +255,7 @@ public class RequestImpl public synchronized void send_deferred() { AsynchInvoke invokeObject = new AsynchInvoke(_orb, this, false); - new sun.misc.ManagedLocalsThread(invokeObject).start(); + new Thread(null, invokeObject, "Async-Request-Invoker-Thread", 0, false).start(); } public synchronized boolean poll_response() diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java index d9dceac7ba8..a9ae337883e 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java @@ -751,12 +751,13 @@ public class Util implements javax.rmi.CORBA.UtilDelegate } } -class KeepAlive extends sun.misc.ManagedLocalsThread +class KeepAlive extends Thread { boolean quit = false; public KeepAlive () { + super(null, null, "Servant-KeepAlive-Thread", 0, false); setDaemon(false); } diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAImpl.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAImpl.java index 546914d623d..3205a5c24be 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAImpl.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAImpl.java @@ -516,7 +516,7 @@ public class POAImpl extends ObjectAdapterBase implements POA // Converted from anonymous class to local class // so that we can call performDestroy() directly. - static class DestroyThread extends sun.misc.ManagedLocalsThread { + static class DestroyThread extends Thread { private boolean wait ; private boolean etherealize ; private boolean debug ; @@ -524,6 +524,7 @@ public class POAImpl extends ObjectAdapterBase implements POA public DestroyThread( boolean etherealize, boolean debug ) { + super(null, null, "POA-Destroy-Thread", 0, false); this.etherealize = etherealize ; this.debug = debug ; } diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAManagerImpl.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAManagerImpl.java index 22610dda9ba..eb51310fcd3 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAManagerImpl.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAManagerImpl.java @@ -357,7 +357,7 @@ public class POAManagerImpl extends org.omg.CORBA.LocalObject implements if (wait_for_completion) deactivator.run() ; else { - Thread thr = new sun.misc.ManagedLocalsThread(deactivator) ; + Thread thr = new Thread(null, deactivator, "POA-Deactivator-Thread", 0, false) ; thr.start() ; } } finally { diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAPolicyMediatorImpl_R_USM.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAPolicyMediatorImpl_R_USM.java index 9e9fce8a47d..1a8badc0930 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAPolicyMediatorImpl_R_USM.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/oa/poa/POAPolicyMediatorImpl_R_USM.java @@ -302,7 +302,7 @@ public class POAPolicyMediatorImpl_R_USM extends POAPolicyMediatorBase_R { throw new WrongPolicy(); } - class Etherealizer extends sun.misc.ManagedLocalsThread { + class Etherealizer extends Thread { private POAPolicyMediatorImpl_R_USM mediator ; private ActiveObjectMap.Key key ; private AOMEntry entry ; @@ -314,6 +314,7 @@ public class POAPolicyMediatorImpl_R_USM extends POAPolicyMediatorBase_R { ActiveObjectMap.Key key, AOMEntry entry, Servant servant, boolean debug ) { + super(null, null, "PAO-Etherealizer-Thread", 0, false); this.mediator = mediator ; this.key = key ; this.entry = entry; diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java index 82da35a7921..007e6b8dc28 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java @@ -691,7 +691,7 @@ public class ORBImpl extends com.sun.corba.se.spi.orb.ORB for (int i = 0; i < req.length; i++) { AsynchInvoke invokeObject = new AsynchInvoke( this, (com.sun.corba.se.impl.corba.RequestImpl)req[i], true); - new sun.misc.ManagedLocalsThread(invokeObject).start(); + new Thread(null, invokeObject, "ORB-Request-Thread", 0, false).start(); } } diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/threadpool/ThreadPoolImpl.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/threadpool/ThreadPoolImpl.java index 9a0e56afc4f..7f3ad89869c 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/threadpool/ThreadPoolImpl.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/threadpool/ThreadPoolImpl.java @@ -459,7 +459,7 @@ public class ThreadPoolImpl implements ThreadPool } - private class WorkerThread extends sun.misc.ManagedLocalsThread implements Closeable + private class WorkerThread extends Thread implements Closeable { private Work currentWork; private int threadId = 0; // unique id for the thread @@ -469,7 +469,7 @@ public class ThreadPoolImpl implements ThreadPool private StringBuffer workerThreadName = new StringBuffer(); WorkerThread(ThreadGroup tg, String threadPoolName) { - super(tg, "Idle"); + super(tg, null, "Idle", 0, false); this.threadId = ThreadPoolImpl.getUniqueThreadId(); this.threadPoolName = threadPoolName; setName(composeWorkerThreadName(threadPoolName, "Idle")); diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/transport/SelectorImpl.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/transport/SelectorImpl.java index 016fd945abf..ac87ef9c932 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/transport/SelectorImpl.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/transport/SelectorImpl.java @@ -61,7 +61,7 @@ import com.sun.corba.se.impl.orbutil.ORBUtility; */ class SelectorImpl extends - sun.misc.ManagedLocalsThread + Thread implements com.sun.corba.se.pept.transport.Selector { @@ -79,6 +79,7 @@ class SelectorImpl public SelectorImpl(ORB orb) { + super(null, null, "ORB-Selector-Thread", 0, false); this.orb = orb; selector = null; selectorStarted = false; @@ -277,7 +278,6 @@ class SelectorImpl public void run() { - setName("SelectorThread"); while (!closed) { try { int n = 0; diff --git a/corba/src/java.corba/share/classes/module-info.java b/corba/src/java.corba/share/classes/module-info.java index 25f79def5cb..23da4b785a9 100644 --- a/corba/src/java.corba/share/classes/module-info.java +++ b/corba/src/java.corba/share/classes/module-info.java @@ -29,8 +29,6 @@ module java.corba { requires java.logging; requires java.naming; requires java.transaction; - // 8148863 - requires jdk.unsupported; exports javax.activity; exports javax.rmi; From d7b161662353d8817648dca8eb8e1f4741b45f69 Mon Sep 17 00:00:00 2001 From: Alexander Kouznetsov Date: Tue, 19 Apr 2016 11:42:29 -0700 Subject: [PATCH 107/222] 8154365: JFrame.setDefaultCloseOperation is prohibited in jtreg Reviewed-by: prr, alexsch --- jdk/test/sanity/client/lib/SwingSet3/README | 2 +- .../src/com/sun/swingset3/demos/button/ButtonDemo.java | 1 - .../src/com/sun/swingset3/demos/combobox/ComboBoxDemo.java | 1 - .../SwingSet3/src/com/sun/swingset3/demos/list/ListDemo.java | 1 - .../src/com/sun/swingset3/demos/optionpane/OptionPaneDemo.java | 1 - .../com/sun/swingset3/demos/progressbar/ProgressBarDemo.java | 1 - .../src/com/sun/swingset3/demos/scrollpane/ScrollPaneDemo.java | 1 - .../src/com/sun/swingset3/demos/spinner/SpinnerDemo.java | 1 - .../src/com/sun/swingset3/demos/splitpane/SplitPaneDemo.java | 1 - .../src/com/sun/swingset3/demos/textfield/TextFieldDemo.java | 1 - .../com/sun/swingset3/demos/togglebutton/ToggleButtonDemo.java | 1 - .../SwingSet3/src/com/sun/swingset3/demos/tree/TreeDemo.java | 1 - .../src/com/sun/swingset3/demos/window/WindowDemo.java | 1 - 13 files changed, 1 insertion(+), 13 deletions(-) diff --git a/jdk/test/sanity/client/lib/SwingSet3/README b/jdk/test/sanity/client/lib/SwingSet3/README index 1952a70cd26..cf0406460ef 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/README +++ b/jdk/test/sanity/client/lib/SwingSet3/README @@ -1,4 +1,4 @@ This content of this src folder was originally taken from SwingSet3 demo project: https://java.net/projects/swingset3/. Then it was modified to increase testability and remove extra content and extra dependencies. -Do NOT modify files in it. \ No newline at end of file +This is NOT the official location of the SwingSet3 demo. \ No newline at end of file diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java index 728e0543b68..e3aa888e5f3 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java @@ -215,7 +215,6 @@ public final class ButtonDemo extends JPanel { javax.swing.SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(buttonDemo); frame.pack(); frame.setVisible(true); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/combobox/ComboBoxDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/combobox/ComboBoxDemo.java index 5fc080f95bb..f204e64437d 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/combobox/ComboBoxDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/combobox/ComboBoxDemo.java @@ -120,7 +120,6 @@ public class ComboBoxDemo extends JPanel implements ActionListener { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ComboBoxDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/list/ListDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/list/ListDemo.java index b8dce72ba9e..02b55129f60 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/list/ListDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/list/ListDemo.java @@ -90,7 +90,6 @@ public final class ListDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ListDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/optionpane/OptionPaneDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/optionpane/OptionPaneDemo.java index 0e8c1e46a13..ca04135c2a1 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/optionpane/OptionPaneDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/optionpane/OptionPaneDemo.java @@ -93,7 +93,6 @@ public class OptionPaneDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new OptionPaneDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/progressbar/ProgressBarDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/progressbar/ProgressBarDemo.java index e49b47926ea..5e9d38bd7a3 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/progressbar/ProgressBarDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/progressbar/ProgressBarDemo.java @@ -64,7 +64,6 @@ public class ProgressBarDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ProgressBarDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/scrollpane/ScrollPaneDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/scrollpane/ScrollPaneDemo.java index 5a492ea53fd..40fb29cfaa6 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/scrollpane/ScrollPaneDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/scrollpane/ScrollPaneDemo.java @@ -64,7 +64,6 @@ public class ScrollPaneDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ScrollPaneDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/spinner/SpinnerDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/spinner/SpinnerDemo.java index 0694a843341..97dbd2d5002 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/spinner/SpinnerDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/spinner/SpinnerDemo.java @@ -58,7 +58,6 @@ public class SpinnerDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new SpinnerDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/splitpane/SplitPaneDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/splitpane/SplitPaneDemo.java index 0bc0cd78f0f..64bc9b2ccaf 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/splitpane/SplitPaneDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/splitpane/SplitPaneDemo.java @@ -86,7 +86,6 @@ public class SplitPaneDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new SplitPaneDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/textfield/TextFieldDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/textfield/TextFieldDemo.java index be7c9a7e7d0..16537bfccf5 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/textfield/TextFieldDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/textfield/TextFieldDemo.java @@ -115,7 +115,6 @@ public class TextFieldDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new TextFieldDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/togglebutton/ToggleButtonDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/togglebutton/ToggleButtonDemo.java index 5adf5f7a62b..625c9fe1fda 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/togglebutton/ToggleButtonDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/togglebutton/ToggleButtonDemo.java @@ -151,7 +151,6 @@ public class ToggleButtonDemo extends JPanel implements ChangeListener { public static void main(String[] args) { JFrame frame = new JFrame(ToggleButtonDemo.class.getAnnotation(DemoProperties.class).value()); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ToggleButtonDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tree/TreeDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tree/TreeDemo.java index 1a4c555945e..e6f8e326571 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tree/TreeDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tree/TreeDemo.java @@ -65,7 +65,6 @@ public class TreeDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new TreeDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java index cf83135d1e8..89b87776ba2 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java @@ -150,7 +150,6 @@ public final class WindowDemo extends JPanel { JFrame frame = new JFrame(); WindowDemo demo = new WindowDemo(); frame.add(demo); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); demo.start(); From 16ee51bad76c18e8fe7531a417073bee50c53998 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Tue, 19 Apr 2016 22:24:51 +0000 Subject: [PATCH 108/222] 8077360: Lower the number of providers created when using ServiceLoader Change ProviderLoader to be singleton and keep providers in java.base internal Reviewed-by: mullan --- jdk/src/java.base/share/classes/module-info.java | 6 +----- .../share/classes/sun/security/jca/ProviderConfig.java | 9 +++++---- .../share/classes/sun/security/jgss/SunProvider.java | 4 +--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java index 8cc37dd7b2d..942c0582ea0 100644 --- a/jdk/src/java.base/share/classes/module-info.java +++ b/jdk/src/java.base/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -300,9 +300,5 @@ module java.base { provides java.nio.file.spi.FileSystemProvider with jdk.internal.jrtfs.JrtFileSystemProvider; - provides java.security.Provider with sun.security.provider.Sun; - provides java.security.Provider with sun.security.rsa.SunRsaSign; - provides java.security.Provider with com.sun.crypto.provider.SunJCE; - provides java.security.Provider with com.sun.net.ssl.internal.ssl.Provider; } diff --git a/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java b/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java index 4ab324914bd..bf65180af6f 100644 --- a/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java +++ b/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -236,9 +236,8 @@ final class ProviderConfig { if (debug != null) { debug.println("Loading provider " + ProviderConfig.this); } - ProviderLoader pl = new ProviderLoader(); try { - Provider p = pl.load(provName); + Provider p = ProviderLoader.INSTANCE.load(provName); if (p != null) { if (hasArgument()) { p = p.configure(argument); @@ -303,9 +302,11 @@ final class ProviderConfig { // Inner class for loading security providers listed in java.security file private static final class ProviderLoader { + static final ProviderLoader INSTANCE = new ProviderLoader(); + private final ServiceLoader services; - ProviderLoader() { + private ProviderLoader() { // VM should already been booted at this point, if not // - Only providers in java.base should be loaded, don't use // ServiceLoader diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/SunProvider.java b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/SunProvider.java index ece97a92afd..3e664d7cccc 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/SunProvider.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/SunProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,8 +97,6 @@ public final class SunProvider extends Provider { } } - public static final SunProvider INSTANCE = new SunProvider(); - public SunProvider() { /* We are the Sun JGSS provider */ super("SunJGSS", 9.0d, INFO); From 89499e85dbb74c8b6b24ee6cc3400528284944b9 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Tue, 19 Apr 2016 22:25:41 +0000 Subject: [PATCH 109/222] 8153371: Remove sun.misc.ManagedLocalsThread from jdk.crypto.pkcs11 Replace usage of ManagedLocalsThread with the new Thread constructor Reviewed-by: xuelei, chegar --- jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java | 4 +--- .../share/classes/sun/security/pkcs11/SunPKCS11.java | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java b/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java index 065b8d2f000..07f4c1bf3e1 100644 --- a/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java +++ b/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * 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,8 +26,6 @@ module jdk.crypto.pkcs11 { // Depends on SunEC provider for EC related functionality requires jdk.crypto.ec; - // 8153371 - requires jdk.unsupported; provides java.security.Provider with sun.security.pkcs11.SunPKCS11; } diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java index de0bef55897..890587ad790 100644 --- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ import javax.security.auth.callback.ConfirmationCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.TextOutputCallback; -import sun.misc.ManagedLocalsThread; import sun.security.util.Debug; import sun.security.util.ResourcesMgr; @@ -816,7 +815,7 @@ public final class SunPKCS11 extends AuthProvider { return; } final TokenPoller poller = new TokenPoller(this); - Thread t = new ManagedLocalsThread(poller, "Poller " + getName()); + Thread t = new Thread(null, poller, "Poller " + getName(), 0, false); t.setDaemon(true); t.setPriority(Thread.MIN_PRIORITY); t.start(); From a6a4976af0bde57f4757919da08d7089a3ebe2c1 Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Tue, 19 Apr 2016 18:09:58 -0700 Subject: [PATCH 110/222] 8137231: sun/security/rsa/SpecTest.java timeout with Agent error: java.lang.Exception Reviewed-by: valeriep --- jdk/test/sun/security/rsa/SpecTest.java | 84 +++++++++++-------------- 1 file changed, 37 insertions(+), 47 deletions(-) diff --git a/jdk/test/sun/security/rsa/SpecTest.java b/jdk/test/sun/security/rsa/SpecTest.java index c13f1d91989..24cddfe3591 100644 --- a/jdk/test/sun/security/rsa/SpecTest.java +++ b/jdk/test/sun/security/rsa/SpecTest.java @@ -20,32 +20,32 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/** + * @test + * @bug 8044199 8137231 + * @key intermittent + * @summary Check same KeyPair's private key and public key have same modulus. + * also check public key's public exponent equals to given spec's public + * exponent. Only key size 1024 is tested with RSAKeyGenParameterSpec.F0 (3). + * @run main SpecTest 512 + * @run main SpecTest 768 + * @run main SpecTest 1024 + * @run main SpecTest 1024 3 + * @run main SpecTest 2048 + * @run main/timeout=240 SpecTest 4096 + * @run main/timeout=240 SpecTest 5120 + */ import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; import java.security.interfaces.RSAKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.RSAKeyGenParameterSpec; -/** - * @test - * @bug 8044199 - * @key intermittent - * @summary Check same KeyPair's private key and public key have same modulus. - * also check public key's public exponent equals to given spec's public - * exponent. - * @run main SpecTest 512 - * @run main SpecTest 768 - * @run main SpecTest 1024 - * @run main SpecTest 2048 - * @run main/timeout=240 SpecTest 4096 - * @run main/timeout=240 SpecTest 5120 - */ public class SpecTest { + /** * ALGORITHM name, fixed as RSA. */ @@ -70,14 +70,14 @@ public class SpecTest { // test the getModulus method if ((priv instanceof RSAKey) && (pub instanceof RSAKey)) { if (!priv.getModulus().equals(pub.getModulus())) { - System.err.println("priv.getModulus() = " + priv.getModulus()); - System.err.println("pub.getModulus() = " + pub.getModulus()); + System.out.println("priv.getModulus() = " + priv.getModulus()); + System.out.println("pub.getModulus() = " + pub.getModulus()); passed = false; } if (!pubExponent.equals(pub.getPublicExponent())) { - System.err.println("pubExponent = " + pubExponent); - System.err.println("pub.getPublicExponent() = " + System.out.println("pubExponent = " + pubExponent); + System.out.println("pub.getPublicExponent() = " + pub.getPublicExponent()); passed = false; } @@ -85,36 +85,26 @@ public class SpecTest { return passed; } - public static void main(String[] args) { - int failCount = 0; + public static void main(String[] args) throws Exception { - // Test key size. - int size = Integer.parseInt(args[0]); + int size = 0; - try { - KeyPairGenerator kpg1 = KeyPairGenerator.getInstance(KEYALG, PROVIDER); - kpg1.initialize(new RSAKeyGenParameterSpec(size, - RSAKeyGenParameterSpec.F4)); - if (!specTest(kpg1.generateKeyPair(), - RSAKeyGenParameterSpec.F4)) { - failCount++; - } - - KeyPairGenerator kpg2 = KeyPairGenerator.getInstance(KEYALG, PROVIDER); - kpg2.initialize(new RSAKeyGenParameterSpec(size, - RSAKeyGenParameterSpec.F0)); - if (!specTest(kpg2.generateKeyPair(), RSAKeyGenParameterSpec.F0)) { - failCount++; - } - } catch (NoSuchAlgorithmException | NoSuchProviderException - | InvalidAlgorithmParameterException ex) { - ex.printStackTrace(System.err); - failCount++; + if (args.length >= 1) { + size = Integer.parseInt(args[0]); + } else { + throw new RuntimeException("Missing keysize to test with"); } - if (failCount != 0) { - throw new RuntimeException("There are " + failCount - + " tests failed."); + BigInteger publicExponent + = (args.length >= 2) ? new BigInteger(args[1]) : RSAKeyGenParameterSpec.F4; + + System.out.println("Running test with key size: " + size + + " and public exponent: " + publicExponent); + + KeyPairGenerator kpg1 = KeyPairGenerator.getInstance(KEYALG, PROVIDER); + kpg1.initialize(new RSAKeyGenParameterSpec(size, publicExponent)); + if (!specTest(kpg1.generateKeyPair(), publicExponent)) { + throw new RuntimeException("Test failed."); } } } From 8658335d619cb041b9b64ec2e7196ce0cb0a67fc Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 20 Apr 2016 10:59:23 +0530 Subject: [PATCH 111/222] 6197099: PrinterJob.getUserName() throws a security exception when user.name permission is not given Reviewed-by: prr, jdv --- .../classes/java/awt/print/PrinterJob.java | 2 + .../awt/print/PrinterJob/GetUserNameTest.java | 49 +++++++++++++++++++ .../print/PrinterJob/GetUserNameTest.policy | 28 +++++++++++ 3 files changed, 79 insertions(+) create mode 100644 jdk/test/java/awt/print/PrinterJob/GetUserNameTest.java create mode 100644 jdk/test/java/awt/print/PrinterJob/GetUserNameTest.policy diff --git a/jdk/src/java.desktop/share/classes/java/awt/print/PrinterJob.java b/jdk/src/java.desktop/share/classes/java/awt/print/PrinterJob.java index 3044cd2413a..5a1cf128607 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/print/PrinterJob.java +++ b/jdk/src/java.desktop/share/classes/java/awt/print/PrinterJob.java @@ -577,6 +577,8 @@ public abstract class PrinterJob { /** * Gets the name of the printing user. * @return the name of the printing user + * @throws SecurityException if a security manager exists and + * PropertyPermission - user.name is not given in the policy file */ public abstract String getUserName(); diff --git a/jdk/test/java/awt/print/PrinterJob/GetUserNameTest.java b/jdk/test/java/awt/print/PrinterJob/GetUserNameTest.java new file mode 100644 index 00000000000..8e35a5f4204 --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/GetUserNameTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 6197099 + * @summary Verifies PrinterJob's getUserName() throws a security exception when + * username permission is not given + * @run main/othervm/java.security.policy=GetUserNameTest.policy GetUserNameTest + */ +import java.awt.print.PrinterJob; + +public class GetUserNameTest { + + public static void main(String args[]) { + System.setSecurityManager(new SecurityManager()); + PrinterJob pj = PrinterJob.getPrinterJob(); + boolean secExcpn = false; + try { + System.out.println(pj.getUserName()); + } catch (SecurityException ex) { + secExcpn = true; + System.out.println("SecurityException thrown as user.name permission " + + "not given"); + } + if (!secExcpn) { + throw new RuntimeException("SecurityException not thrown"); + } + } +} diff --git a/jdk/test/java/awt/print/PrinterJob/GetUserNameTest.policy b/jdk/test/java/awt/print/PrinterJob/GetUserNameTest.policy new file mode 100644 index 00000000000..b7b7d70df3d --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/GetUserNameTest.policy @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.lang.RuntimePermission "createSecurityManager"; + permission java.lang.RuntimePermission "usePolicy"; + permission java.lang.RuntimePermission "queuePrintJob"; +}; From d03b60789684f8a9e96b47c89b05b3c2e639c26a Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Tue, 19 Apr 2016 23:01:06 -0700 Subject: [PATCH 112/222] 8153781: Issue in XMLScanner: EXPECTED_SQUARE_BRACKET_TO_CLOSE_INTERNAL_SUBSET when skipping large DOCTYPE section with CRLF at wrong place Reviewed-by: joehw --- .../internal/impl/XML11EntityScanner.java | 25 +++--- .../internal/impl/XMLDTDScannerImpl.java | 55 +++++++----- .../impl/XMLDocumentFragmentScannerImpl.java | 14 +-- .../internal/impl/XMLDocumentScannerImpl.java | 17 ++-- .../internal/impl/XMLEntityScanner.java | 61 +++++++------ .../xerces/internal/impl/XMLScanner.java | 14 +-- .../internal/impl/msg/XMLMessages.properties | 1 + .../impl/msg/XMLMessages_de.properties | 1 + .../impl/msg/XMLMessages_es.properties | 1 + .../impl/msg/XMLMessages_fr.properties | 1 + .../impl/msg/XMLMessages_it.properties | 1 + .../xerces/internal/util/HTTPInputSource.java | 30 +++---- .../javax/xml/jaxp/unittest/TEST.properties | 3 +- .../XMLEventReaderTest/Bug6668115Test.java | 3 +- .../stream/XMLEventReaderTest/Bug8153781.java | 90 +++++++++++++++++++ 15 files changed, 210 insertions(+), 107 deletions(-) create mode 100644 jaxp/test/javax/xml/jaxp/unittest/stream/XMLEventReaderTest/Bug8153781.java diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java index a425067224c..8e1eaef54e1 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java @@ -1,15 +1,16 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* - * Copyright 2005 The Apache Software Foundation. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -24,7 +25,6 @@ import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; import com.sun.org.apache.xerces.internal.util.XML11Char; import com.sun.org.apache.xerces.internal.util.XMLChar; import com.sun.org.apache.xerces.internal.util.XMLStringBuffer; -import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager.Limit; import com.sun.org.apache.xerces.internal.xni.QName; import com.sun.org.apache.xerces.internal.xni.XMLString; @@ -815,7 +815,7 @@ public class XML11EntityScanner load(0, true, true); } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { - invokeListeners(0); + invokeListeners(1); fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; load(1, false, false); fCurrentEntity.position = 0; @@ -960,7 +960,7 @@ public class XML11EntityScanner load(0, true, true); } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { - invokeListeners(0); + invokeListeners(1); fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; load(1, false, false); fCurrentEntity.startPosition = 0; @@ -1397,7 +1397,7 @@ public class XML11EntityScanner fCurrentEntity.lineNumber++; fCurrentEntity.columnNumber = 1; if (fCurrentEntity.position == fCurrentEntity.count - 1) { - invokeListeners(0); + invokeListeners(1); fCurrentEntity.ch[0] = (char)c; entityChanged = load(1, true, false); if (!entityChanged) { @@ -1446,8 +1446,9 @@ public class XML11EntityScanner fCurrentEntity.lineNumber++; fCurrentEntity.columnNumber = 1; if (fCurrentEntity.position == fCurrentEntity.count - 1) { + invokeListeners(1); fCurrentEntity.ch[0] = (char)c; - entityChanged = load(1, true, true); + entityChanged = load(1, true, false); if (!entityChanged) { // the load change the position to be 1, // need to restore it when entity not changed diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java index 4daa5f0e333..d695936f67d 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java @@ -3,13 +3,14 @@ */ /* - * Copyright 2005 The Apache Software Foundation. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,17 +20,17 @@ */ package com.sun.org.apache.xerces.internal.impl; -import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar; -import java.io.EOFException; -import java.io.IOException; +import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; - +import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; +import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler; import com.sun.org.apache.xerces.internal.util.SymbolTable; import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl; import com.sun.org.apache.xerces.internal.util.XMLChar; import com.sun.org.apache.xerces.internal.util.XMLStringBuffer; - +import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer; +import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler; import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler; import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; @@ -41,11 +42,9 @@ import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner; import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; import com.sun.org.apache.xerces.internal.xni.Augmentations; -import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; -import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler; -import com.sun.org.apache.xerces.internal.impl.Constants; -import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer; -import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; +import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar; +import java.io.EOFException; +import java.io.IOException; /** * This class is responsible for scanning the declarations found @@ -387,15 +386,25 @@ implements XMLDTDScanner, XMLComponent, XMLEntityHandler { */ @Override public boolean skipDTD(boolean supportDTD) throws IOException { - if (!supportDTD) { - fStringBuffer.clear(); - if (!fEntityScanner.scanData("]", fStringBuffer)) { - fEntityScanner.fCurrentEntity.position--; - } + if (supportDTD) + return false; - return true; + fStringBuffer.clear(); + while (fEntityScanner.scanData("]", fStringBuffer)) { + int c = fEntityScanner.peekChar(); + if (c != -1) { + if (XMLChar.isHighSurrogate(c)) { + scanSurrogates(fStringBuffer); + } + if (isInvalidLiteral(c)) { + reportFatalError("InvalidCharInDTD", + new Object[] { Integer.toHexString(c) }); + fEntityScanner.scanChar(); + } + } } - return false; + fEntityScanner.fCurrentEntity.position--; + return true; } // diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java index e31e838c8e8..c817111e067 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java @@ -3,13 +3,14 @@ */ /* - * Copyright 2005 The Apache Software Foundation. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +19,6 @@ * limitations under the License. */ - package com.sun.org.apache.xerces.internal.impl; import com.sun.xml.internal.stream.XMLBufferListener; diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java index 7f1bbf10226..235d27ba5d8 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java @@ -3,13 +3,14 @@ */ /* - * Copyright 2005 The Apache Software Foundation. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +21,6 @@ package com.sun.org.apache.xerces.internal.impl; - import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDDescription; import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager; import com.sun.org.apache.xerces.internal.util.NamespaceSupport; @@ -1106,8 +1106,7 @@ public class XMLDocumentScannerImpl if (!moreToScan) { // end doctype declaration if (!fEntityScanner.skipChar(']')) { - reportFatalError("EXPECTED_SQUARE_BRACKET_TO_CLOSE_INTERNAL_SUBSET", - null); + reportFatalError("DoctypedeclNotClosed", new Object[]{fDoctypeName}); } fEntityScanner.skipSpaces(); if (!fEntityScanner.skipChar('>')) { diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java index 1c0eca636a8..b7922312371 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java @@ -1,15 +1,16 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. */ /* - * Copyright 2005 The Apache Software Foundation. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,8 +21,6 @@ package com.sun.org.apache.xerces.internal.impl; - - import com.sun.org.apache.xerces.internal.impl.io.ASCIIReader; import com.sun.org.apache.xerces.internal.impl.io.UCSReader; import com.sun.org.apache.xerces.internal.impl.io.UTF8Reader; @@ -44,8 +43,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.util.ArrayList; import java.util.Locale; -import java.util.Vector; /** * Implements the entity scanner methods. @@ -58,11 +57,10 @@ import java.util.Vector; */ public class XMLEntityScanner implements XMLLocator { - - protected Entity.ScannedEntity fCurrentEntity = null ; + protected Entity.ScannedEntity fCurrentEntity = null; protected int fBufferSize = XMLEntityManager.DEFAULT_BUFFER_SIZE; - protected XMLEntityManager fEntityManager ; + protected XMLEntityManager fEntityManager; /** Security manager. */ protected XMLSecurityManager fSecurityManager = null; @@ -72,8 +70,9 @@ public class XMLEntityScanner implements XMLLocator { /** Debug switching readers for encodings. */ private static final boolean DEBUG_ENCODINGS = false; + /** Listeners which should know when load is being called */ - private Vector listeners = new Vector(); + private ArrayList listeners = new ArrayList<>(); private static final boolean [] VALID_NAMES = new boolean[127]; @@ -140,9 +139,11 @@ public class XMLEntityScanner implements XMLLocator { VALID_NAMES[58]=true; VALID_NAMES[95]=true; } - // SAPJVM: Remember, that the XML version has explicitly been set, + + // Remember, that the XML version has explicitly been set, // so that XMLStreamReader.getVersion() can find that out. - boolean xmlVersionSetExplicitly = false; + protected boolean xmlVersionSetExplicitly = false; + // // Constructors // @@ -257,7 +258,7 @@ public class XMLEntityScanner implements XMLLocator { * @param xmlVersion the XML version of the current entity */ public final void setXMLVersion(String xmlVersion) { - xmlVersionSetExplicitly = true; // SAPJVM + xmlVersionSetExplicitly = true; fCurrentEntity.xmlVersion = xmlVersion; } // setXMLVersion(String) @@ -546,8 +547,7 @@ public class XMLEntityScanner implements XMLLocator { // scan character int c = fCurrentEntity.ch[fCurrentEntity.position++]; - if (c == '\n' || - (c == '\r' && isExternal)) { + if (c == '\n' || (c == '\r' && isExternal)) { fCurrentEntity.lineNumber++; fCurrentEntity.columnNumber = 1; if (fCurrentEntity.position == fCurrentEntity.count) { @@ -953,7 +953,7 @@ public class XMLEntityScanner implements XMLLocator { if (fCurrentEntity.position == fCurrentEntity.count) { load(0, true, true); } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { - invokeListeners(0); + invokeListeners(1); fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; load(1, false, false); fCurrentEntity.position = 0; @@ -1105,7 +1105,7 @@ public class XMLEntityScanner implements XMLLocator { if (fCurrentEntity.position == fCurrentEntity.count) { load(0, true, true); } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { - invokeListeners(0); + invokeListeners(1); fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; load(1, false, false); fCurrentEntity.position = 0; @@ -1256,8 +1256,8 @@ public class XMLEntityScanner implements XMLLocator { *

    * Note: The characters are consumed. *

    - * Note: This assumes that the length of the delimiter - * and that the delimiter contains at least one character. + * Note: This assumes that the delimiter contains at + * least one character. *

    * Note: This method does not guarantee to return * the longest run of character data. This method may return before @@ -1436,7 +1436,7 @@ public class XMLEntityScanner implements XMLLocator { } while (!done); return !done; - } // scanData(String,XMLString) + } // scanData(String, XMLStringBuffer) /** * Skips a character appearing immediately on the input. @@ -1558,7 +1558,7 @@ public class XMLEntityScanner implements XMLLocator { fCurrentEntity.lineNumber++; fCurrentEntity.columnNumber = 1; if (fCurrentEntity.position == fCurrentEntity.count - 1) { - invokeListeners(0); + invokeListeners(1); fCurrentEntity.ch[0] = (char)c; entityChanged = load(1, true, false); if (!entityChanged){ @@ -1727,8 +1727,7 @@ public class XMLEntityScanner implements XMLLocator { final int length = s.length; //first make sure that required capacity is avaible if(arrangeCapacity(length, false)){ - int beforeSkip = fCurrentEntity.position ; - int afterSkip = fCurrentEntity.position + length ; + int beforeSkip = fCurrentEntity.position; if(DEBUG_SKIP_STRING){ System.out.println("skipString,length = " + new String(s) + "," + length); @@ -2107,8 +2106,9 @@ public class XMLEntityScanner implements XMLLocator { * is being changed. */ public void registerListener(XMLBufferListener listener) { - if(!listeners.contains(listener)) + if (!listeners.contains(listener)) { listeners.add(listener); + } } /** @@ -2116,9 +2116,8 @@ public class XMLEntityScanner implements XMLLocator { * @param loadPos Starting position from which new data is being loaded into scanner buffer. */ public void invokeListeners(int loadPos){ - for(int i=0;i''. + DoctypedeclNotClosed = The document type declaration for root element type \"{0}\" must be closed with '']''. PEReferenceWithinMarkup = The parameter entity reference \"%{0};\" cannot occur within markup in the internal subset of the DTD. MSG_MARKUP_NOT_RECOGNIZED_IN_DTD = The markup declarations contained or pointed to by the document type declaration must be well-formed. # 2.10 White Space Handling diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_de.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_de.properties index c82bc5b80d0..55c9d3a3c92 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_de.properties +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_de.properties @@ -145,6 +145,7 @@ MSG_SPACE_REQUIRED_BEFORE_ROOT_ELEMENT_TYPE_IN_DOCTYPEDECL = Leerstelle nach "" enden. + DoctypedeclNotClosed = Dokumenttypdeklaration f\u00FCr Root-Elementtyp "{0}" muss mit "]" abgeschlossen werden. PEReferenceWithinMarkup = Parameterentit\u00E4tsreferenz "%{0};" darf nicht in Markup in der internen Teilmenge der DTD vorkommen. MSG_MARKUP_NOT_RECOGNIZED_IN_DTD = Die Markup-Deklarationen, die in der Dokumenttypdeklaration enthalten sind bzw. auf die von der Dokumenttypdeklaration verwiesen wird, m\u00FCssen ordnungsgem\u00E4\u00DF formatiert sein. # 2.10 White Space Handling diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_es.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_es.properties index 1243b215cec..51491f84075 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_es.properties +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_es.properties @@ -145,6 +145,7 @@ MSG_SPACE_REQUIRED_BEFORE_ROOT_ELEMENT_TYPE_IN_DOCTYPEDECL = Es necesario un espacio en blanco despu\u00E9s de "''. + DoctypedeclNotClosed = La declaraci\u00F3n de tipo de documento para el tipo de elemento ra\u00EDz "{0}" debe cerrar en '']''. PEReferenceWithinMarkup = La referencia de entidad del par\u00E1metro "%{0};" no puede producirse en el marcador en el subconjunto interno del DTD. MSG_MARKUP_NOT_RECOGNIZED_IN_DTD = Las declaraciones de marcador que se incluyen o a las que apunta la declaraci\u00F3n de tipo de documento deben tener el formato correcto. # 2.10 White Space Handling diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_fr.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_fr.properties index 5a2b76c13b7..2be672257f3 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_fr.properties +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_fr.properties @@ -145,6 +145,7 @@ MSG_SPACE_REQUIRED_BEFORE_ROOT_ELEMENT_TYPE_IN_DOCTYPEDECL = Un espace est obligatoire apr\u00E8s "''. + DoctypedeclNotClosed = La d\u00E9claration de type de document pour le type d''\u00E9l\u00E9ment racine "{0}" doit se conclure par '']''. PEReferenceWithinMarkup = La r\u00E9f\u00E9rence d''entit\u00E9 de param\u00E8tre "%{0};" ne peut pas survenir dans le balisage du sous-ensemble interne de la DTD. MSG_MARKUP_NOT_RECOGNIZED_IN_DTD = Les d\u00E9clarations de balisage contenues dans la d\u00E9claration de type de document ou sur lesquelles pointe cette derni\u00E8re doivent avoir un format correct. # 2.10 White Space Handling diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_it.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_it.properties index 1f8ec89276a..aa229f49bf2 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_it.properties +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages_it.properties @@ -145,6 +145,7 @@ MSG_SPACE_REQUIRED_BEFORE_ROOT_ELEMENT_TYPE_IN_DOCTYPEDECL = \u00C8 richiesto uno spazio dopo "''. + DoctypedeclNotClosed = La dichiarazione del tipo di documento per il tipo di elemento radice "{0}" deve chiudere con '']''. PEReferenceWithinMarkup = Il riferimento di entit\u00E0 di parametro "%{0};" non pu\u00F2 essere presente nel markup del set secondario interno del DTD. MSG_MARKUP_NOT_RECOGNIZED_IN_DTD = Le dichiarazioni di markup contenute o indicate dalla dichiarazione del tipo di documento devono avere un formato corretto. # 2.10 White Space Handling diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/HTTPInputSource.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/HTTPInputSource.java index bdd0750d0fa..c9bbed93511 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/HTTPInputSource.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/HTTPInputSource.java @@ -1,15 +1,16 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. */ + /* - * Copyright 2004,2005 The Apache Software Foundation. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,17 +18,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.sun.org.apache.xerces.internal.util; -import java.io.InputStream; -import java.io.Reader; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; +import java.io.InputStream; +import java.io.Reader; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; /** * This class represents an input source for an XML resource diff --git a/jaxp/test/javax/xml/jaxp/unittest/TEST.properties b/jaxp/test/javax/xml/jaxp/unittest/TEST.properties index 93da2fdba82..b6e235b5124 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/TEST.properties +++ b/jaxp/test/javax/xml/jaxp/unittest/TEST.properties @@ -4,5 +4,6 @@ TestNG.dirs = . lib.dirs = /javax/xml/jaxp/libs # Declare module dependency -modules=java.xml/com.sun.org.apache.xerces.internal.jaxp \ +modules=java.xml/com.sun.org.apache.xerces.internal.impl \ + java.xml/com.sun.org.apache.xerces.internal.jaxp \ java.xml/com.sun.org.apache.xml.internal.serialize diff --git a/jaxp/test/javax/xml/jaxp/unittest/stream/XMLEventReaderTest/Bug6668115Test.java b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLEventReaderTest/Bug6668115Test.java index c56e7569c3c..188d003621a 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/stream/XMLEventReaderTest/Bug6668115Test.java +++ b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLEventReaderTest/Bug6668115Test.java @@ -28,7 +28,6 @@ import java.io.File; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.events.XMLEvent; import org.testng.Assert; import org.testng.annotations.Test; @@ -74,7 +73,7 @@ public class Bug6668115Test { er.nextTag(); er.nextTag(); - XMLEvent event = er.peek(); + er.peek(); System.out.println(er.getElementText()); er.nextTag(); System.out.println(er.getElementText()); diff --git a/jaxp/test/javax/xml/jaxp/unittest/stream/XMLEventReaderTest/Bug8153781.java b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLEventReaderTest/Bug8153781.java new file mode 100644 index 00000000000..f973b3bf33d --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLEventReaderTest/Bug8153781.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package stream.XMLEventReaderTest; + +import java.io.StringReader; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.sun.org.apache.xerces.internal.impl.XMLEntityManager; + +/* + * @bug 8153781 + * @summary Test if method skipDTD of class XMLDTDScannerImpl will correctly skip the DTD section, + * even if a call to XMLEntityScanner.scanData for skipping to the closing ']' returns true. + */ +public class Bug8153781 { + public static int DOCTYPE_SECTION_LENGTH = XMLEntityManager.DEFAULT_BUFFER_SIZE * 2; + public static int DOCUMENT_LENGTH = DOCTYPE_SECTION_LENGTH + 4096; + + public String createXMLDocument(int doctypeoffset) { + StringBuilder xmlcontentbuilder = new StringBuilder(DOCUMENT_LENGTH); + xmlcontentbuilder.append("\r\n"); + xmlcontentbuilder.append("\r\n"); + xmlcontentbuilder.append(" \r\n"); + xmlcontentbuilder.append(" ]\r\n"); + xmlcontentbuilder.append(">\r\n"); + xmlcontentbuilder.append("\r\n"); + xmlcontentbuilder.append("\r\n"); + System.out.println("Document length:" + xmlcontentbuilder.length()); + return xmlcontentbuilder.toString(); + } + + public void runReader(XMLInputFactory factory, int offset) throws XMLStreamException { + StringReader stringReader = new StringReader(createXMLDocument(offset)); + XMLEventReader reader = factory.createXMLEventReader(stringReader); + + while (reader.hasNext()) { + XMLEvent event = reader.nextEvent(); + System.out.println("Event Type: " + event.getEventType()); + } + } + + @Test + public void test() { + try { + XMLInputFactory factory = XMLInputFactory.newInstance(); + factory.setProperty(XMLInputFactory.SUPPORT_DTD, false); + for (int i = 0; i < 3; i++) { + runReader(factory, i); + } + } catch (XMLStreamException xe) { + xe.printStackTrace(); + Assert.fail(xe.getMessage()); + } + } +} From 4b1ef0a20be4c6444aea5b8f281135cc7a6a5595 Mon Sep 17 00:00:00 2001 From: Frank Yuan Date: Tue, 19 Apr 2016 23:56:52 -0700 Subject: [PATCH 113/222] 8078820: Test deploying a XML parser as a module Reviewed-by: joehw, alanb --- .../jaxp/libs/jdk/testlibrary/Asserts.java | 566 +++++++++++++++++ .../libs/jdk/testlibrary/CompilerUtils.java | 81 +++ .../libs/jdk/testlibrary/JDKToolFinder.java | 111 ++++ .../libs/jdk/testlibrary/JDKToolLauncher.java | 136 ++++ .../libs/jdk/testlibrary/OutputAnalyzer.java | 576 +++++++++++++++++ .../libs/jdk/testlibrary/OutputBuffer.java | 113 ++++ .../jaxp/libs/jdk/testlibrary/Platform.java | 213 +++++++ .../libs/jdk/testlibrary/ProcessTools.java | 579 ++++++++++++++++++ .../xml/jaxp/libs/jdk/testlibrary/README.txt | 1 + .../libs/jdk/testlibrary/StreamPumper.java | 204 ++++++ .../xml/jaxp/libs/jdk/testlibrary/Utils.java | 365 +++++++++++ .../BasicModularXMLParserTest.java | 120 ++++ .../LayerModularXMLParserTest.java | 187 ++++++ .../src/test/module-info.java | 27 + .../src/test/test/XMLFactoryHelper.java | 55 ++ .../ServiceProviderTest/src/unnamed/Main.java | 107 ++++ .../src/xmlprovider1/module-info.java | 34 + .../xp1/DocumentBuilderFactoryImpl.java | 57 ++ .../xp1/SAXParserFactoryImpl.java | 53 ++ .../xmlprovider1/xp1/SchemaFactoryImpl.java | 77 +++ .../xp1/TransformerFactoryImpl.java | 97 +++ .../xmlprovider1/xp1/XMLInputFactoryImpl.java | 166 +++++ .../xp1/XMLOutputFactoryImpl.java | 94 +++ .../xmlprovider1/xp1/XPathFactoryImpl.java | 65 ++ .../src/xmlprovider2/module-info.java | 29 + .../xmlprovider2/xp2/DatatypeFactoryImpl.java | 73 +++ .../xmlprovider2/xp2/XMLEventFactoryImpl.java | 180 ++++++ .../javax/xml/jaxp/module/TEST.properties | 5 + 28 files changed, 4371 insertions(+) create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Asserts.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/CompilerUtils.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/JDKToolFinder.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/JDKToolLauncher.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/OutputAnalyzer.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/OutputBuffer.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Platform.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/ProcessTools.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/README.txt create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/StreamPumper.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Utils.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/BasicModularXMLParserTest.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/LayerModularXMLParserTest.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/module-info.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/test/XMLFactoryHelper.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/unnamed/Main.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/module-info.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/DocumentBuilderFactoryImpl.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/SAXParserFactoryImpl.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/SchemaFactoryImpl.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/TransformerFactoryImpl.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XMLInputFactoryImpl.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XMLOutputFactoryImpl.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XPathFactoryImpl.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/module-info.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/DatatypeFactoryImpl.java create mode 100644 jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/XMLEventFactoryImpl.java create mode 100644 jaxp/test/javax/xml/jaxp/module/TEST.properties diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Asserts.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Asserts.java new file mode 100644 index 00000000000..594b12e3ede --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Asserts.java @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; + +import java.util.Objects; + +/** + * Asserts that can be used for verifying assumptions in tests. + * + * An assertion will throw a {@link RuntimeException} if the assertion isn't true. + * All the asserts can be imported into a test by using a static import: + * + *

    + * {@code
    + * import static jdk.testlibrary.Asserts.*;
    + * }
    + *
    + * Always provide a message describing the assumption if the line number of the
    + * failing assertion isn't enough to understand why the assumption failed. For
    + * example, if the assertion is in a loop or in a method that is called
    + * multiple times, then the line number won't provide enough context to
    + * understand the failure.
    + * 
    + * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} + */ +@Deprecated +public class Asserts { + + /** + * Shorthand for {@link #assertLessThan(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThan(Comparable, Comparable) + */ + public static > void assertLT(T lhs, T rhs) { + assertLessThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThan(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertLessThan(Comparable, Comparable, String) + */ + public static > void assertLT(T lhs, T rhs, String msg) { + assertLessThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThan(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThan(Comparable, Comparable, String) + */ + public static > void assertLessThan(T lhs, T rhs) { + assertLessThan(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is less than {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static >void assertLessThan(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) < 0)) { + msg = Objects.toString(msg, "assertLessThan") + + ": expected that " + Objects.toString(lhs) + + " < " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThanOrEqual(Comparable, Comparable) + */ + public static > void assertLTE(T lhs, T rhs) { + assertLessThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertLessThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertLTE(T lhs, T rhs, String msg) { + assertLessThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThanOrEqual(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertLessThanOrEqual(T lhs, T rhs) { + assertLessThanOrEqual(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is less than or equal to {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static > void assertLessThanOrEqual(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) <= 0)) { + msg = Objects.toString(msg, "assertLessThanOrEqual") + + ": expected that " + Objects.toString(lhs) + + " <= " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertEquals(Object, Object)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertEquals(Object, Object) + */ + public static void assertEQ(Object lhs, Object rhs) { + assertEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertEquals(Object, Object, String)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertEquals(Object, Object, String) + */ + public static void assertEQ(Object lhs, Object rhs, String msg) { + assertEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertEquals(java.lang.Object, java.lang.Object, java.lang.String)} with a default message. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertEquals(Object, Object, String) + */ + public static void assertEquals(Object lhs, Object rhs) { + assertEquals(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertEquals(Object lhs, Object rhs, String msg) { + if ((lhs != rhs) && ((lhs == null) || !(lhs.equals(rhs)))) { + msg = Objects.toString(msg, "assertEquals") + + ": expected " + Objects.toString(lhs) + + " to equal " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Calls {@link #assertSame(java.lang.Object, java.lang.Object, java.lang.String)} with a default message. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertSame(Object, Object, String) + */ + public static void assertSame(Object lhs, Object rhs) { + assertSame(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is the same as {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertSame(Object lhs, Object rhs, String msg) { + if (lhs != rhs) { + msg = Objects.toString(msg, "assertSame") + + ": expected " + Objects.toString(lhs) + + " to equal " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertGreaterThanOrEqual(Comparable, Comparable) + */ + public static > void assertGTE(T lhs, T rhs) { + assertGreaterThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertGreaterThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertGTE(T lhs, T rhs, String msg) { + assertGreaterThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertGreaterThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs) { + assertGreaterThanOrEqual(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is greater than or equal to {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) >= 0)) { + msg = Objects.toString(msg, "assertGreaterThanOrEqual") + + ": expected " + Objects.toString(lhs) + + " >= " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertGreaterThan(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertGreaterThan(Comparable, Comparable) + */ + public static > void assertGT(T lhs, T rhs) { + assertGreaterThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThan(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs the left hand value + * @param rhs the right hand value + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertGreaterThan(Comparable, Comparable, String) + */ + public static > void assertGT(T lhs, T rhs, String msg) { + assertGreaterThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThan(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs the left hand value + * @param rhs the right hand value + * @see #assertGreaterThan(Comparable, Comparable, String) + */ + public static > void assertGreaterThan(T lhs, T rhs) { + assertGreaterThan(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is greater than {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static > void assertGreaterThan(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) > 0)) { + msg = Objects.toString(msg, "assertGreaterThan") + + ": expected " + Objects.toString(lhs) + + " > " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertNotEquals(Object, Object)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertNotEquals(Object, Object) + */ + public static void assertNE(Object lhs, Object rhs) { + assertNotEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertNotEquals(Object, Object, String)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertNotEquals(Object, Object, String) + */ + public static void assertNE(Object lhs, Object rhs, String msg) { + assertNotEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertNotEquals(Object, Object, String)} with a default message. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertNotEquals(Object, Object, String) + */ + public static void assertNotEquals(Object lhs, Object rhs) { + assertNotEquals(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is not equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertNotEquals(Object lhs, Object rhs, String msg) { + if ((lhs == rhs) || (lhs != null && lhs.equals(rhs))) { + msg = Objects.toString(msg, "assertNotEquals") + + ": expected " + Objects.toString(lhs) + + " to not equal " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Calls {@link #assertNull(Object, String)} with a default message. + * + * @param o The reference assumed to be null. + * @see #assertNull(Object, String) + */ + public static void assertNull(Object o) { + assertNull(o, null); + } + + /** + * Asserts that {@code o} is null. + * + * @param o The reference assumed to be null. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertNull(Object o, String msg) { + assertEquals(o, null, msg); + } + + /** + * Calls {@link #assertNotNull(Object, String)} with a default message. + * + * @param o The reference assumed not to be null, + * @see #assertNotNull(Object, String) + */ + public static void assertNotNull(Object o) { + assertNotNull(o, null); + } + + /** + * Asserts that {@code o} is not null. + * + * @param o The reference assumed not to be null, + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertNotNull(Object o, String msg) { + assertNotEquals(o, null, msg); + } + + /** + * Calls {@link #assertFalse(boolean, String)} with a default message. + * + * @param value The value assumed to be false. + * @see #assertFalse(boolean, String) + */ + public static void assertFalse(boolean value) { + assertFalse(value, null); + } + + /** + * Asserts that {@code value} is {@code false}. + * + * @param value The value assumed to be false. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertFalse(boolean value, String msg) { + if (value) { + msg = Objects.toString(msg, "assertFalse") + + ": expected false, was true"; + fail(msg); + } + } + + /** + * Calls {@link #assertTrue(boolean, String)} with a default message. + * + * @param value The value assumed to be true. + * @see #assertTrue(boolean, String) + */ + public static void assertTrue(boolean value) { + assertTrue(value, null); + } + + /** + * Asserts that {@code value} is {@code true}. + * + * @param value The value assumed to be true. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertTrue(boolean value, String msg) { + if (!value) { + msg = Objects.toString(msg, "assertTrue") + + ": expected true, was false"; + fail(msg); + } + } + + private static > int compare(T lhs, T rhs, String msg) { + if (lhs == null || rhs == null) { + fail(lhs, rhs, msg + ": values must be non-null:", ","); + } + return lhs.compareTo(rhs); + } + + /** + * Returns a string formatted with a message and expected and actual values. + * @param lhs the actual value + * @param rhs the expected value + * @param message the actual value + * @param relation the asserted relationship between lhs and rhs + * @return a formatted string + */ + public static String format(Object lhs, Object rhs, String message, String relation) { + StringBuilder sb = new StringBuilder(80); + if (message != null) { + sb.append(message); + sb.append(' '); + } + sb.append("<"); + sb.append(Objects.toString(lhs)); + sb.append("> "); + sb.append(Objects.toString(relation, ",")); + sb.append(" <"); + sb.append(Objects.toString(rhs)); + sb.append(">"); + return sb.toString(); + } + + /** + * Fail reports a failure with message fail. + * + * @throws RuntimeException always + */ + public static void fail() { + fail("fail"); + } + + /** + * Fail reports a failure with a message. + * @param message for the failure + * @throws RuntimeException always + */ + public static void fail(String message) { + throw new RuntimeException(message); + } + + /** + * Fail reports a failure with a formatted message. + * + * @param lhs the actual value + * @param rhs the expected value + * @param message to be format before the expected and actual values + * @param relation the asserted relationship between lhs and rhs + * @throws RuntimeException always + */ + public static void fail(Object lhs, Object rhs, String message, String relation) { + throw new RuntimeException(format(lhs, rhs, message, relation)); + } + + /** + * Fail reports a failure with a message and a cause. + * @param message to be format before the expected and actual values + * @param cause the exception that caused this failure + * @throws RuntimeException always + */ + public static void fail(String message, Throwable cause) { + throw new RuntimeException(message, cause); + } + +} diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/CompilerUtils.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/CompilerUtils.java new file mode 100644 index 00000000000..afabfd7cc52 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/CompilerUtils.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; + +import javax.tools.JavaCompiler; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * This class consists exclusively of static utility methods for invoking the + * java compiler. + */ + +public final class CompilerUtils { + private CompilerUtils() { } + + /** + * Compile all the java sources in {@code /**} to + * {@code /**}. The destination directory will be created if + * it doesn't exist. + * + * All warnings/errors emitted by the compiler are output to System.out/err. + * + * @return true if the compilation is successful + * + * @throws IOException if there is an I/O error scanning the source tree or + * creating the destination directory + */ + public static boolean compile(Path source, Path destination, String ... options) + throws IOException + { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager jfm = compiler.getStandardFileManager(null, null, null); + + List sources + = Files.find(source, Integer.MAX_VALUE, + (file, attrs) -> (file.toString().endsWith(".java"))) + .collect(Collectors.toList()); + + Files.createDirectories(destination); + jfm.setLocation(StandardLocation.CLASS_PATH, Collections.EMPTY_LIST); + jfm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, + Arrays.asList(destination)); + + List opts = Arrays.asList(options); + JavaCompiler.CompilationTask task + = compiler.getTask(null, jfm, null, opts, null, + jfm.getJavaFileObjectsFromPaths(sources)); + + return task.call(); + } +} diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/JDKToolFinder.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/JDKToolFinder.java new file mode 100644 index 00000000000..c4815229eb7 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/JDKToolFinder.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; + +import java.io.FileNotFoundException; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} + */ +@Deprecated +public final class JDKToolFinder { + + private JDKToolFinder() { + } + + /** + * Returns the full path to an executable in jdk/bin based on System + * property {@code test.jdk} or {@code compile.jdk} (both are set by the jtreg test suite) + * + * @return Full path to an executable in jdk/bin + */ + public static String getJDKTool(String tool) { + + // First try to find the executable in test.jdk + try { + return getTool(tool, "test.jdk"); + } catch (FileNotFoundException e) { + + } + + // Now see if it's available in compile.jdk + try { + return getTool(tool, "compile.jdk"); + } catch (FileNotFoundException e) { + throw new RuntimeException("Failed to find " + tool + + ", looked in test.jdk (" + System.getProperty("test.jdk") + + ") and compile.jdk (" + System.getProperty("compile.jdk") + ")"); + } + } + + /** + * Returns the full path to an executable in jdk/bin based on System + * property {@code compile.jdk} + * + * @return Full path to an executable in jdk/bin + */ + public static String getCompileJDKTool(String tool) { + try { + return getTool(tool, "compile.jdk"); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * Returns the full path to an executable in jdk/bin based on System + * property {@code test.jdk} + * + * @return Full path to an executable in jdk/bin + */ + public static String getTestJDKTool(String tool) { + try { + return getTool(tool, "test.jdk"); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + private static String getTool(String tool, String property) throws FileNotFoundException { + String jdkPath = System.getProperty(property); + + if (jdkPath == null) { + throw new RuntimeException( + "System property '" + property + "' not set. This property is normally set by jtreg. " + + "When running test separately, set this property using '-D" + property + "=/path/to/jdk'."); + } + + Path toolName = Paths.get("bin", tool + (Platform.isWindows() ? ".exe" : "")); + + Path jdkTool = Paths.get(jdkPath, toolName.toString()); + if (!jdkTool.toFile().exists()) { + throw new FileNotFoundException("Could not find file " + jdkTool.toAbsolutePath()); + } + + return jdkTool.toAbsolutePath().toString(); + } +} diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/JDKToolLauncher.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/JDKToolLauncher.java new file mode 100644 index 00000000000..777e8cf5336 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/JDKToolLauncher.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A utility for constructing command lines for starting JDK tool processes. + * + * The JDKToolLauncher can in particular be combined with a + * java.lang.ProcessBuilder to easily run a JDK tool. For example, the following + * code run {@code jmap -heap} against a process with GC logging turned on for + * the {@code jmap} process: + * + *
    + * {@code
    + * JDKToolLauncher jmap = JDKToolLauncher.create("jmap")
    + *                                       .addVMArg("-Xlog:gc*=debug")
    + *                                       .addToolArg("-heap")
    + *                                       .addToolArg(pid);
    + * ProcessBuilder pb = new ProcessBuilder(jmap.getCommand());
    + * Process p = pb.start();
    + * }
    + * 
    + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} + */ +@Deprecated +public class JDKToolLauncher { + private final String executable; + private final List vmArgs = new ArrayList(); + private final List toolArgs = new ArrayList(); + + private JDKToolLauncher(String tool, boolean useCompilerJDK) { + if (useCompilerJDK) { + executable = JDKToolFinder.getJDKTool(tool); + } else { + executable = JDKToolFinder.getTestJDKTool(tool); + } + vmArgs.addAll(Arrays.asList(ProcessTools.getPlatformSpecificVMArgs())); + } + + /** + * Creates a new JDKToolLauncher for the specified tool. Using tools path + * from the compiler JDK. + * + * @param tool + * The name of the tool + * @return A new JDKToolLauncher + */ + public static JDKToolLauncher create(String tool) { + return new JDKToolLauncher(tool, true); + } + + /** + * Creates a new JDKToolLauncher for the specified tool in the Tested JDK. + * + * @param tool + * The name of the tool + * + * @return A new JDKToolLauncher + */ + public static JDKToolLauncher createUsingTestJDK(String tool) { + return new JDKToolLauncher(tool, false); + } + + /** + * Adds an argument to the JVM running the tool. + * + * The JVM arguments are passed to the underlying JVM running the tool. + * Arguments will automatically be prepended with "-J". + * + * Any platform specific arguments required for running the tool are + * automatically added. + * + * + * @param arg + * The argument to VM running the tool + * @return The JDKToolLauncher instance + */ + public JDKToolLauncher addVMArg(String arg) { + vmArgs.add(arg); + return this; + } + + /** + * Adds an argument to the tool. + * + * @param arg + * The argument to the tool + * @return The JDKToolLauncher instance + */ + public JDKToolLauncher addToolArg(String arg) { + toolArgs.add(arg); + return this; + } + + /** + * Returns the command that can be used for running the tool. + * + * @return An array whose elements are the arguments of the command. + */ + public String[] getCommand() { + List command = new ArrayList(); + command.add(executable); + // Add -J in front of all vmArgs + for (String arg : vmArgs) { + command.add("-J" + arg); + } + command.addAll(toolArgs); + return command.toArray(new String[command.size()]); + } +} diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/OutputAnalyzer.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/OutputAnalyzer.java new file mode 100644 index 00000000000..839c3228294 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/OutputAnalyzer.java @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; + +import static jdk.testlibrary.Asserts.*; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utility class for verifying output and exit value from a {@code Process}. + * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + * + */ +@Deprecated +public final class OutputAnalyzer { + private final OutputBuffer output; + private final String stdout; + private final String stderr; + private final int exitValue; // useless now. output contains exit value. + + /** + * Create an OutputAnalyzer, a utility class for verifying output and exit + * value from a Process. + *

    + * OutputAnalyzer should never be instantiated directly - + * use {@linkplain ProcessTools#executeProcess(ProcessBuilder)} instead + * + * @param process + * Process to analyze + * @throws IOException + * If an I/O error occurs. + */ + OutputAnalyzer(Process process) throws IOException { + output = new OutputBuffer(process); + exitValue = -1; + this.stdout = null; + this.stderr = null; + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output. + * + * @param buf + * String buffer to analyze + */ + OutputAnalyzer(String buf) { + this(buf, buf); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param stdout + * stdout buffer to analyze + * @param stderr + * stderr buffer to analyze + */ + OutputAnalyzer(String stdout, String stderr) { + this.output = null; + this.stdout = stdout; + this.stderr = stderr; + exitValue = -1; + } + + /** + * Verify that the stdout and stderr contents of output buffer contains the + * string + * + * @param expectedString + * String that buffer should contain + * @throws RuntimeException + * If the string was not found + */ + public OutputAnalyzer shouldContain(String expectedString) { + if (!getStdout().contains(expectedString) + && !getStderr().contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + + "' missing from stdout/stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer contains the string + * + * @param expectedString + * String that buffer should contain + * @throws RuntimeException + * If the string was not found + */ + public OutputAnalyzer stdoutShouldContain(String expectedString) { + if (!getStdout().contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + + "' missing from stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer contains the string + * + * @param expectedString + * String that buffer should contain + * @throws RuntimeException + * If the string was not found + */ + public OutputAnalyzer stderrShouldContain(String expectedString) { + if (!getStderr().contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + + "' missing from stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer does not + * contain the string + * + * @param notExpectedString + * String that the buffer should not contain + * @throws RuntimeException + * If the string was found + */ + public OutputAnalyzer shouldNotContain(String notExpectedString) { + if (getStdout().contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + + "' found in stdout \n"); + } + if (getStderr().contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + + "' found in stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer does not contain the + * string + * + * @param notExpectedString + * String that the buffer should not contain + * @throws RuntimeException + * If the string was found + */ + public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) { + if (getStdout().contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + + "' found in stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer does not contain the + * string + * + * @param notExpectedString + * String that the buffer should not contain + * @throws RuntimeException + * If the string was found + */ + public OutputAnalyzer stderrShouldNotContain(String notExpectedString) { + if (getStderr().contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + + "' found in stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException + * If the pattern was not found + */ + public OutputAnalyzer shouldMatch(String pattern) { + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE) + .matcher(getStdout()); + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE) + .matcher(getStderr()); + if (!stdoutMatcher.find() && !stderrMatcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stdout/stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer matches the pattern + * + * @param pattern + * @throws RuntimeException + * If the pattern was not found + */ + public OutputAnalyzer stdoutShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher( + getStdout()); + if (!matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer matches the pattern + * + * @param pattern + * @throws RuntimeException + * If the pattern was not found + */ + public OutputAnalyzer stderrShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher( + getStderr()); + if (!matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer does not + * match the pattern + * + * @param pattern + * @throws RuntimeException + * If the pattern was found + */ + public OutputAnalyzer shouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher( + getStdout()); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + "' found in stdout: '" + + matcher.group() + "' \n"); + } + matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(getStderr()); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + "' found in stderr: '" + + matcher.group() + "' \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException + * If the pattern was found + */ + public OutputAnalyzer stdoutShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher( + getStdout()); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + "' found in stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException + * If the pattern was found + */ + public OutputAnalyzer stderrShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher( + getStderr()); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + "' found in stderr \n"); + } + return this; + } + + /** + * Get the captured group of the first string matching the pattern. stderr + * is searched before stdout. + * + * @param pattern + * The multi-line pattern to match + * @param group + * The group to capture + * @return The matched string or null if no match was found + */ + public String firstMatch(String pattern, int group) { + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE) + .matcher(getStderr()); + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE) + .matcher(getStdout()); + if (stderrMatcher.find()) { + return stderrMatcher.group(group); + } + if (stdoutMatcher.find()) { + return stdoutMatcher.group(group); + } + return null; + } + + /** + * Get the first string matching the pattern. stderr is searched before + * stdout. + * + * @param pattern + * The multi-line pattern to match + * @return The matched string or null if no match was found + */ + public String firstMatch(String pattern) { + return firstMatch(pattern, 0); + } + + /** + * Verify the exit value of the process + * + * @param expectedExitValue + * Expected exit value from process + * @throws RuntimeException + * If the exit value from the process did not match the expected + * value + */ + public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) { + if (getExitValue() != expectedExitValue) { + reportDiagnosticSummary(); + throw new RuntimeException("Expected to get exit value of [" + + expectedExitValue + "]\n"); + } + return this; + } + + /** + * Report summary that will help to diagnose the problem Currently includes: + * - standard input produced by the process under test - standard output - + * exit code Note: the command line is printed by the ProcessTools + */ + private OutputAnalyzer reportDiagnosticSummary() { + String msg = " stdout: [" + getStdout() + "];\n" + " stderr: [" + getStderr() + + "]\n" + " exitValue = " + getExitValue() + "\n"; + + System.err.println(msg); + return this; + } + + /** + * Get the contents of the output buffer (stdout and stderr) + * + * @return Content of the output buffer + */ + public String getOutput() { + return getStdout() + getStderr(); + } + + /** + * Get the contents of the stdout buffer + * + * @return Content of the stdout buffer + */ + public String getStdout() { + return output == null ? stdout : output.getStdout(); + } + + /** + * Get the contents of the stderr buffer + * + * @return Content of the stderr buffer + */ + public String getStderr() { + return output == null ? stderr : output.getStderr(); + } + + /** + * Get the process exit value + * + * @return Process exit value + */ + public int getExitValue() { + return output == null ? exitValue : output.getExitValue(); + } + + + /** + * Print the stdout buffer to the given {@code PrintStream}. + * + * @return this OutputAnalyzer + */ + public OutputAnalyzer outputTo(PrintStream out) { + out.println(getStdout()); + return this; + } + + /** + * Print the stderr buffer to the given {@code PrintStream}. + * + * @return this OutputAnalyzer + */ + public OutputAnalyzer errorTo(PrintStream out) { + out.println(getStderr()); + return this; + } + + + /** + * Get the contents of the output buffer (stdout and stderr) as list of strings. + * Output will be split by system property 'line.separator'. + * + * @return Contents of the output buffer as list of strings + */ + public List asLines() { + return asLines(getOutput()); + } + + private List asLines(String buffer) { + List l = new ArrayList<>(); + String[] a = buffer.split(Utils.NEW_LINE); + for (String string : a) { + l.add(string); + } + return l; + } + + /** + * Check if there is a line matching {@code pattern} and return its index + * + * @param pattern Matching pattern + * @return Index of first matching line + */ + private int indexOf(List lines, String pattern) { + for (int i = 0; i < lines.size(); i++) { + if (lines.get(i).matches(pattern)) { + return i; + } + } + return -1; + } + + /** + * @see #shouldMatchByLine(String, String, String) + */ + public int shouldMatchByLine(String pattern) { + return shouldMatchByLine(null, null, pattern); + } + + /** + * @see #stdoutShouldMatchByLine(String, String, String) + */ + public int stdoutShouldMatchByLine(String pattern) { + return stdoutShouldMatchByLine(null, null, pattern); + } + + /** + * @see #shouldMatchByLine(String, String, String) + */ + public int shouldMatchByLineFrom(String from, String pattern) { + return shouldMatchByLine(from, null, pattern); + } + + /** + * @see #shouldMatchByLine(String, String, String) + */ + public int shouldMatchByLineTo(String to, String pattern) { + return shouldMatchByLine(null, to, pattern); + } + + /** + * Verify that the stdout and stderr contents of output buffer match the + * {@code pattern} line by line. The whole output could be matched or + * just a subset of it. + * + * @param from + * The line from where output will be matched. + * Set {@code from} to null for matching from the first line. + * @param to + * The line until where output will be matched. + * Set {@code to} to null for matching until the last line. + * @param pattern + * Matching pattern + * @return Count of lines which match the {@code pattern} + */ + public int shouldMatchByLine(String from, String to, String pattern) { + return shouldMatchByLine(getOutput(), from, to, pattern); + } + + /** + * Verify that the stdout contents of output buffer matches the + * {@code pattern} line by line. The whole stdout could be matched or + * just a subset of it. + * + * @param from + * The line from where stdout will be matched. + * Set {@code from} to null for matching from the first line. + * @param to + * The line until where stdout will be matched. + * Set {@code to} to null for matching until the last line. + * @param pattern + * Matching pattern + * @return Count of lines which match the {@code pattern} + */ + public int stdoutShouldMatchByLine(String from, String to, String pattern) { + return shouldMatchByLine(getStdout(), from, to, pattern); + } + + private int shouldMatchByLine(String buffer, String from, String to, String pattern) { + List lines = asLines(buffer); + + int fromIndex = 0; + if (from != null) { + fromIndex = indexOf(lines, from); + assertGreaterThan(fromIndex, -1, + "The line/pattern '" + from + "' from where the output should match can not be found"); + } + + int toIndex = lines.size(); + if (to != null) { + toIndex = indexOf(lines, to); + assertGreaterThan(toIndex, -1, + "The line/pattern '" + to + "' until where the output should match can not be found"); + } + + List subList = lines.subList(fromIndex, toIndex); + int matchedCount = 0; + for (String line : subList) { + assertTrue(line.matches(pattern), + "The line '" + line + "' does not match pattern '" + pattern + "'"); + matchedCount++; + } + + return matchedCount; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/OutputBuffer.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/OutputBuffer.java new file mode 100644 index 00000000000..c8a5d7aab12 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/OutputBuffer.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; + +import java.io.ByteArrayOutputStream; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + */ +@Deprecated +class OutputBuffer { + private static class OutputBufferException extends RuntimeException { + private static final long serialVersionUID = 8528687792643129571L; + + public OutputBufferException(Throwable cause) { + super(cause); + } + } + + private final Process p; + private final Future outTask; + private final Future errTask; + private final ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream(); + private final ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream(); + + /** + * Create an OutputBuffer, a class for storing and managing stdout and + * stderr results separately + * + * @param stdout + * stdout result + * @param stderr + * stderr result + */ + OutputBuffer(Process p) { + this.p = p; + StreamPumper outPumper = new StreamPumper(p.getInputStream(), + stdoutBuffer); + StreamPumper errPumper = new StreamPumper(p.getErrorStream(), + stderrBuffer); + + outTask = outPumper.process(); + errTask = errPumper.process(); + } + + /** + * Returns the stdout result + * + * @return stdout result + */ + public String getStdout() { + try { + outTask.get(); + return stdoutBuffer.toString(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new OutputBufferException(e); + } catch (ExecutionException | CancellationException e) { + throw new OutputBufferException(e); + } + } + + /** + * Returns the stderr result + * + * @return stderr result + */ + public String getStderr() { + try { + errTask.get(); + return stderrBuffer.toString(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new OutputBufferException(e); + } catch (ExecutionException | CancellationException e) { + throw new OutputBufferException(e); + } + } + + public int getExitValue() { + try { + return p.waitFor(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new OutputBufferException(e); + } + } +} diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Platform.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Platform.java new file mode 100644 index 00000000000..523e6e6a074 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Platform.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; +import java.util.regex.Pattern; +import java.io.RandomAccessFile; +import java.io.FileNotFoundException; +import java.io.IOException; + +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} + */ +@Deprecated +public class Platform { + private static final String osName = System.getProperty("os.name"); + private static final String dataModel = System.getProperty("sun.arch.data.model"); + private static final String vmVersion = System.getProperty("java.vm.version"); + private static final String jdkDebug = System.getProperty("jdk.debug"); + private static final String osArch = System.getProperty("os.arch"); + private static final String vmName = System.getProperty("java.vm.name"); + private static final String userName = System.getProperty("user.name"); + private static final String compiler = System.getProperty("sun.management.compiler"); + + public static boolean isClient() { + return vmName.endsWith(" Client VM"); + } + + public static boolean isServer() { + return vmName.endsWith(" Server VM"); + } + + public static boolean isGraal() { + return vmName.endsWith(" Graal VM"); + } + + public static boolean isMinimal() { + return vmName.endsWith(" Minimal VM"); + } + + public static boolean isEmbedded() { + return vmName.contains("Embedded"); + } + + public static boolean isTieredSupported() { + return compiler.contains("Tiered Compilers"); + } + + + public static boolean is32bit() { + return dataModel.equals("32"); + } + + public static boolean is64bit() { + return dataModel.equals("64"); + } + + public static boolean isAix() { + return isOs("aix"); + } + + public static boolean isLinux() { + return isOs("linux"); + } + + public static boolean isOSX() { + return isOs("mac"); + } + + public static boolean isSolaris() { + return isOs("sunos"); + } + + public static boolean isWindows() { + return isOs("win"); + } + + private static boolean isOs(String osname) { + return osName.toLowerCase().startsWith(osname.toLowerCase()); + } + + public static String getOsName() { + return osName; + } + + public static boolean isDebugBuild() { + return (jdkDebug.toLowerCase().contains("debug")); + } + + public static String getVMVersion() { + return vmVersion; + } + + // Returns true for sparc and sparcv9. + public static boolean isSparc() { + return isArch("sparc.*"); + } + + public static boolean isARM() { + return isArch("arm.*"); + } + + public static boolean isPPC() { + return isArch("ppc.*"); + } + + public static boolean isX86() { + // On Linux it's 'i386', Windows 'x86' without '_64' suffix. + return isArch("(i386)|(x86(?!_64))"); + } + + public static boolean isX64() { + // On OSX it's 'x86_64' and on other (Linux, Windows and Solaris) platforms it's 'amd64' + return isArch("(amd64)|(x86_64)"); + } + + private static boolean isArch(String archnameRE) { + return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE) + .matcher(osArch) + .matches(); + } + + public static String getOsArch() { + return osArch; + } + + /** + * Return a boolean for whether we expect to be able to attach + * the SA to our own processes on this system. + */ + public static boolean shouldSAAttach() + throws IOException { + + if (isAix()) { + return false; // SA not implemented. + } else if (isLinux()) { + return canPtraceAttachLinux(); + } else if (isOSX()) { + return canAttachOSX(); + } else { + // Other platforms expected to work: + return true; + } + } + + /** + * On Linux, first check the SELinux boolean "deny_ptrace" and return false + * as we expect to be denied if that is "1". + */ + public static boolean canPtraceAttachLinux() + throws IOException { + + // SELinux deny_ptrace: + try(RandomAccessFile file = new RandomAccessFile("/sys/fs/selinux/booleans/deny_ptrace", "r")) { + if (file.readByte() != '0') { + return false; + } + } + catch(FileNotFoundException ex) { + // Ignored + } + + // YAMA enhanced security ptrace_scope: + // 0 - a process can PTRACE_ATTACH to any other process running under the same uid + // 1 - restricted ptrace: a process must be a children of the inferior or user is root + // 2 - only processes with CAP_SYS_PTRACE may use ptrace or user is root + // 3 - no attach: no processes may use ptrace with PTRACE_ATTACH + + try(RandomAccessFile file = new RandomAccessFile("/proc/sys/kernel/yama/ptrace_scope", "r")) { + byte yama_scope = file.readByte(); + if (yama_scope == '3') { + return false; + } + + if (!userName.equals("root") && yama_scope != '0') { + return false; + } + } + catch(FileNotFoundException ex) { + // Ignored + } + + // Otherwise expect to be permitted: + return true; + } + + /** + * On OSX, expect permission to attach only if we are root. + */ + public static boolean canAttachOSX() { + return userName.equals("root"); + } +} diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/ProcessTools.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/ProcessTools.java new file mode 100644 index 00000000000..35cffc1c994 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/ProcessTools.java @@ -0,0 +1,579 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Predicate; +import java.util.function.Consumer; +import java.util.stream.Collectors; + + +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + */ +@Deprecated +public final class ProcessTools { + private static final class LineForwarder extends StreamPumper.LinePump { + private final PrintStream ps; + private final String prefix; + LineForwarder(String prefix, PrintStream os) { + this.ps = os; + this.prefix = prefix; + } + @Override + protected void processLine(String line) { + ps.println("[" + prefix + "] " + line); + } + } + + private ProcessTools() { + } + + /** + *

    Starts a process from its builder.

    + * The default redirects of STDOUT and STDERR are started + * @param name The process name + * @param processBuilder The process builder + * @return Returns the initialized process + * @throws IOException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder) + throws IOException { + return startProcess(name, processBuilder, (Consumer)null); + } + + /** + *

    Starts a process from its builder.

    + * The default redirects of STDOUT and STDERR are started + *

    It is possible to monitor the in-streams via the provided {@code consumer} + * @param name The process name + * @param consumer {@linkplain Consumer} instance to process the in-streams + * @param processBuilder The process builder + * @return Returns the initialized process + * @throws IOException + */ + @SuppressWarnings("overloads") + public static Process startProcess(String name, + ProcessBuilder processBuilder, + Consumer consumer) + throws IOException { + try { + return startProcess(name, processBuilder, consumer, null, -1, TimeUnit.NANOSECONDS); + } catch (InterruptedException | TimeoutException e) { + // will never happen + throw new RuntimeException(e); + } + } + + /** + *

    Starts a process from its builder.

    + * The default redirects of STDOUT and STDERR are started + *

    + * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT + *

    + * @param name The process name + * @param processBuilder The process builder + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @param timeout The timeout for the warmup waiting; -1 = no wait; 0 = wait forever + * @param unit The timeout {@linkplain TimeUnit} + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Predicate linePredicate, + long timeout, + TimeUnit unit) + throws IOException, InterruptedException, TimeoutException { + return startProcess(name, processBuilder, null, linePredicate, timeout, unit); + } + + /** + *

    Starts a process from its builder.

    + * The default redirects of STDOUT and STDERR are started + *

    + * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT and monitor the + * in-streams via the provided {@linkplain Consumer} + *

    + * @param name The process name + * @param processBuilder The process builder + * @param lineConsumer The {@linkplain Consumer} the lines will be forwarded to + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @param timeout The timeout for the warmup waiting; -1 = no wait; 0 = wait forever + * @param unit The timeout {@linkplain TimeUnit} + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Consumer lineConsumer, + final Predicate linePredicate, + long timeout, + TimeUnit unit) + throws IOException, InterruptedException, TimeoutException { + System.out.println("["+name+"]:" + processBuilder.command().stream().collect(Collectors.joining(" "))); + Process p = processBuilder.start(); + StreamPumper stdout = new StreamPumper(p.getInputStream()); + StreamPumper stderr = new StreamPumper(p.getErrorStream()); + + stdout.addPump(new LineForwarder(name, System.out)); + stderr.addPump(new LineForwarder(name, System.err)); + if (lineConsumer != null) { + StreamPumper.LinePump pump = new StreamPumper.LinePump() { + @Override + protected void processLine(String line) { + lineConsumer.accept(line); + } + }; + stdout.addPump(pump); + stderr.addPump(pump); + } + + + CountDownLatch latch = new CountDownLatch(1); + if (linePredicate != null) { + StreamPumper.LinePump pump = new StreamPumper.LinePump() { + @Override + protected void processLine(String line) { + if (latch.getCount() > 0 && linePredicate.test(line)) { + latch.countDown(); + } + } + }; + stdout.addPump(pump); + stderr.addPump(pump); + } else { + latch.countDown(); + } + final Future stdoutTask = stdout.process(); + final Future stderrTask = stderr.process(); + + try { + if (timeout > -1) { + if (timeout == 0) { + latch.await(); + } else { + if (!latch.await(Utils.adjustTimeout(timeout), unit)) { + throw new TimeoutException(); + } + } + } + } catch (TimeoutException | InterruptedException e) { + System.err.println("Failed to start a process (thread dump follows)"); + for(Map.Entry s : Thread.getAllStackTraces().entrySet()) { + printStack(s.getKey(), s.getValue()); + } + + if (p.isAlive()) { + p.destroyForcibly(); + } + + stdoutTask.cancel(true); + stderrTask.cancel(true); + throw e; + } + + return new ProcessImpl(p, stdoutTask, stderrTask); + } + + /** + *

    Starts a process from its builder.

    + * The default redirects of STDOUT and STDERR are started + *

    + * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT. The warm-up will + * wait indefinitely. + *

    + * @param name The process name + * @param processBuilder The process builder + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + @SuppressWarnings("overloads") + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Predicate linePredicate) + throws IOException, InterruptedException, TimeoutException { + return startProcess(name, processBuilder, linePredicate, 0, TimeUnit.SECONDS); + } + + /** + * Get the process id of the current running Java process + * + * @return Process id + */ + public static long getProcessId() { + return ProcessHandle.current().getPid(); + } + + /** + * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) + * + * @return String[] with platform specific arguments, empty if there are + * none + */ + public static String[] getPlatformSpecificVMArgs() { + String osName = System.getProperty("os.name"); + String dataModel = System.getProperty("sun.arch.data.model"); + + if (osName.equals("SunOS") && dataModel.equals("64")) { + return new String[] { "-d64" }; + } + + return new String[] {}; + } + + /** + * Create ProcessBuilder using the java launcher from the jdk to be tested, + * and with any platform specific arguments prepended. + * + * @param command Arguments to pass to the java command. + * @return The ProcessBuilder instance representing the java command. + */ + public static ProcessBuilder createJavaProcessBuilder(String... command) + throws Exception { + return createJavaProcessBuilder(false, command); + } + + /** + * Create ProcessBuilder using the java launcher from the jdk to be tested, + * and with any platform specific arguments prepended. + * + * @param addTestVmAndJavaOptions If true, adds test.vm.opts and test.java.opts + * to the java arguments. + * @param command Arguments to pass to the java command. + * @return The ProcessBuilder instance representing the java command. + */ + public static ProcessBuilder createJavaProcessBuilder(boolean addTestVmAndJavaOptions, String... command) throws Exception { + String javapath = JDKToolFinder.getJDKTool("java"); + + ArrayList args = new ArrayList<>(); + args.add(javapath); + Collections.addAll(args, getPlatformSpecificVMArgs()); + + if (addTestVmAndJavaOptions) { + // -cp is needed to make sure the same classpath is used whether the test is + // run in AgentVM mode or OtherVM mode. It was added to the hotspot version + // of this API as part of 8077608. However, for the jdk version it is only + // added when addTestVmAndJavaOptions is true in order to minimize + // disruption to existing JDK tests, which have yet to be tested with -cp + // being added. At some point -cp should always be added to be consistent + // with what the hotspot version does. + args.add("-cp"); + args.add(System.getProperty("java.class.path")); + Collections.addAll(args, Utils.getTestJavaOpts()); + } + + Collections.addAll(args, command); + + // Reporting + StringBuilder cmdLine = new StringBuilder(); + for (String cmd : args) + cmdLine.append(cmd).append(' '); + System.out.println("Command line: [" + cmdLine.toString() + "]"); + + return new ProcessBuilder(args.toArray(new String[args.size()])); + } + + private static void printStack(Thread t, StackTraceElement[] stack) { + System.out.println("\t" + t + + " stack: (length = " + stack.length + ")"); + if (t != null) { + for (StackTraceElement stack1 : stack) { + System.out.println("\t" + stack1); + } + System.out.println(); + } + } + + /** + * Executes a test java process, waits for it to finish and returns the process output. + * The default options from jtreg, test.vm.opts and test.java.opts, are added. + * The java from the test.jdk is used to execute the command. + * + * The command line will be like: + * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds + * + * The java process will have exited before this method returns. + * + * @param cmds User specifed arguments. + * @return The output from the process. + */ + public static OutputAnalyzer executeTestJava(String... options) throws Exception { + ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(options)); + return executeProcess(pb); + } + + /** + * @deprecated Use executeTestJava instead + */ + public static OutputAnalyzer executeTestJvm(String... options) throws Exception { + return executeTestJava(options); + } + + /** + * Executes a process, waits for it to finish and returns the process output. + * The process will have exited before this method returns. + * @param pb The ProcessBuilder to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Exception { + return executeProcess(pb, null); + } + + /** + * Executes a process, pipe some text into its STDIN, waits for it + * to finish and returns the process output. The process will have exited + * before this method returns. + * @param pb The ProcessBuilder to execute. + * @param input The text to pipe into STDIN. Can be null. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeProcess(ProcessBuilder pb, String input) + throws Exception { + OutputAnalyzer output = null; + Process p = null; + boolean failed = false; + try { + p = pb.start(); + if (input != null) { + try (OutputStream os = p.getOutputStream(); + PrintStream ps = new PrintStream(os)) { + ps.print(input); + ps.flush(); + } + } + output = new OutputAnalyzer(p); + p.waitFor(); + + return output; + } catch (Throwable t) { + if (p != null) { + p.destroyForcibly().waitFor(); + } + + failed = true; + System.out.println("executeProcess() failed: " + t); + throw t; + } finally { + if (failed) { + System.err.println(getProcessLog(pb, output)); + } + } + } + + /** + * Executes a process, waits for it to finish and returns the process output. + * + * The process will have exited before this method returns. + * + * @param cmds The command line to execute. + * @return The output from the process. + */ + public static OutputAnalyzer executeProcess(String... cmds) throws Throwable { + return executeProcess(new ProcessBuilder(cmds)); + } + + /** + * Used to log command line, stdout, stderr and exit code from an executed process. + * @param pb The executed process. + * @param output The output from the process. + */ + public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) { + String stderr = output == null ? "null" : output.getStderr(); + String stdout = output == null ? "null" : output.getStdout(); + String exitValue = output == null ? "null": Integer.toString(output.getExitValue()); + StringBuilder logMsg = new StringBuilder(); + final String nl = System.getProperty("line.separator"); + logMsg.append("--- ProcessLog ---" + nl); + logMsg.append("cmd: " + getCommandLine(pb) + nl); + logMsg.append("exitvalue: " + exitValue + nl); + logMsg.append("stderr: " + stderr + nl); + logMsg.append("stdout: " + stdout + nl); + + return logMsg.toString(); + } + + /** + * @return The full command line for the ProcessBuilder. + */ + public static String getCommandLine(ProcessBuilder pb) { + if (pb == null) { + return "null"; + } + StringBuilder cmd = new StringBuilder(); + for (String s : pb.command()) { + cmd.append(s).append(" "); + } + return cmd.toString().trim(); + } + + /** + * Executes a process, waits for it to finish, prints the process output + * to stdout, and returns the process output. + * + * The process will have exited before this method returns. + * + * @param cmds The command line to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeCommand(String... cmds) + throws Throwable { + String cmdLine = Arrays.stream(cmds).collect(Collectors.joining(" ")); + System.out.println("Command line: [" + cmdLine + "]"); + OutputAnalyzer analyzer = ProcessTools.executeProcess(cmds); + System.out.println(analyzer.getOutput()); + return analyzer; + } + + /** + * Executes a process, waits for it to finish, prints the process output + * to stdout and returns the process output. + * + * The process will have exited before this method returns. + * + * @param pb The ProcessBuilder to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeCommand(ProcessBuilder pb) + throws Throwable { + String cmdLine = pb.command().stream().collect(Collectors.joining(" ")); + System.out.println("Command line: [" + cmdLine + "]"); + OutputAnalyzer analyzer = ProcessTools.executeProcess(pb); + System.out.println(analyzer.getOutput()); + return analyzer; + } + + private static class ProcessImpl extends Process { + + private final Process p; + private final Future stdoutTask; + private final Future stderrTask; + + public ProcessImpl(Process p, Future stdoutTask, Future stderrTask) { + this.p = p; + this.stdoutTask = stdoutTask; + this.stderrTask = stderrTask; + } + + @Override + public OutputStream getOutputStream() { + return p.getOutputStream(); + } + + @Override + public InputStream getInputStream() { + return p.getInputStream(); + } + + @Override + public InputStream getErrorStream() { + return p.getErrorStream(); + } + + @Override + public int waitFor() throws InterruptedException { + int rslt = p.waitFor(); + waitForStreams(); + return rslt; + } + + @Override + public int exitValue() { + return p.exitValue(); + } + + @Override + public void destroy() { + p.destroy(); + } + + @Override + public long getPid() { + return p.getPid(); + } + + @Override + public boolean isAlive() { + return p.isAlive(); + } + + @Override + public Process destroyForcibly() { + return p.destroyForcibly(); + } + + @Override + public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException { + boolean rslt = p.waitFor(timeout, unit); + if (rslt) { + waitForStreams(); + } + return rslt; + } + + private void waitForStreams() throws InterruptedException { + try { + stdoutTask.get(); + } catch (ExecutionException e) { + } + try { + stderrTask.get(); + } catch (ExecutionException e) { + } + } + } +} diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/README.txt b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/README.txt new file mode 100644 index 00000000000..c4fd572cd04 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/README.txt @@ -0,0 +1 @@ +These files are copies of the corresponding files in test/lib/testlibrary/ from jdk repo. diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/StreamPumper.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/StreamPumper.java new file mode 100644 index 00000000000..2f3c205db3c --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/StreamPumper.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + */ +@Deprecated +public final class StreamPumper implements Runnable { + + private static final int BUF_SIZE = 256; + + /** + * Pump will be called by the StreamPumper to process the incoming data + */ + abstract public static class Pump { + abstract void register(StreamPumper d); + } + + /** + * OutputStream -> Pump adapter + */ + final public static class StreamPump extends Pump { + private final OutputStream out; + public StreamPump(OutputStream out) { + this.out = out; + } + + @Override + void register(StreamPumper sp) { + sp.addOutputStream(out); + } + } + + /** + * Used to process the incoming data line-by-line + */ + abstract public static class LinePump extends Pump { + @Override + final void register(StreamPumper sp) { + sp.addLineProcessor(this); + } + + abstract protected void processLine(String line); + } + + private final InputStream in; + private final Set outStreams = new HashSet<>(); + private final Set linePumps = new HashSet<>(); + + private final AtomicBoolean processing = new AtomicBoolean(false); + private final FutureTask processingTask = new FutureTask<>(this, null); + + public StreamPumper(InputStream in) { + this.in = in; + } + + /** + * Create a StreamPumper that reads from in and writes to out. + * + * @param in + * The stream to read from. + * @param out + * The stream to write to. + */ + public StreamPumper(InputStream in, OutputStream out) { + this(in); + this.addOutputStream(out); + } + + /** + * Implements Thread.run(). Continuously read from {@code in} and write to + * {@code out} until {@code in} has reached end of stream. Abort on + * interruption. Abort on IOExceptions. + */ + @Override + public void run() { + try (BufferedInputStream is = new BufferedInputStream(in)) { + ByteArrayOutputStream lineBos = new ByteArrayOutputStream(); + byte[] buf = new byte[BUF_SIZE]; + int len = 0; + int linelen = 0; + + while ((len = is.read(buf)) > 0 && !Thread.interrupted()) { + for(OutputStream out : outStreams) { + out.write(buf, 0, len); + } + if (!linePumps.isEmpty()) { + int i = 0; + int lastcrlf = -1; + while (i < len) { + if (buf[i] == '\n' || buf[i] == '\r') { + int bufLinelen = i - lastcrlf - 1; + if (bufLinelen > 0) { + lineBos.write(buf, lastcrlf + 1, bufLinelen); + } + linelen += bufLinelen; + + if (linelen > 0) { + lineBos.flush(); + final String line = lineBos.toString(); + linePumps.stream().forEach((lp) -> { + lp.processLine(line); + }); + lineBos.reset(); + linelen = 0; + } + lastcrlf = i; + } + + i++; + } + if (lastcrlf == -1) { + lineBos.write(buf, 0, len); + linelen += len; + } else if (lastcrlf < len - 1) { + lineBos.write(buf, lastcrlf + 1, len - lastcrlf - 1); + linelen += len - lastcrlf - 1; + } + } + } + + } catch (IOException e) { + e.printStackTrace(); + } finally { + for(OutputStream out : outStreams) { + try { + out.flush(); + } catch (IOException e) {} + } + try { + in.close(); + } catch (IOException e) {} + } + } + + final void addOutputStream(OutputStream out) { + outStreams.add(out); + } + + final void addLineProcessor(LinePump lp) { + linePumps.add(lp); + } + + final public StreamPumper addPump(Pump ... pump) { + if (processing.get()) { + throw new IllegalStateException("Can not modify pumper while " + + "processing is in progress"); + } + for(Pump p : pump) { + p.register(this); + } + return this; + } + + final public Future process() { + if (!processing.compareAndSet(false, true)) { + throw new IllegalStateException("Can not re-run the processing"); + } + Thread t = new Thread(new Runnable() { + @Override + public void run() { + processingTask.run(); + } + }); + t.setDaemon(true); + t.start(); + + return processingTask; + } +} diff --git a/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Utils.java b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Utils.java new file mode 100644 index 00000000000..c76339107c8 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/jdk/testlibrary/Utils.java @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.testlibrary; + +import static jdk.testlibrary.Asserts.assertTrue; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.Arrays; +import java.util.Collections; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.concurrent.TimeUnit; +import java.util.function.BooleanSupplier; +import java.util.function.Function; + +/** + * Common library for various test helper functions. + * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} + */ +@Deprecated +public final class Utils { + + /** + * Returns the sequence used by operating system to separate lines. + */ + public static final String NEW_LINE = System.getProperty("line.separator"); + + /** + * Returns the value of 'test.vm.opts'system property. + */ + public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim(); + + /** + * Returns the value of 'test.java.opts'system property. + */ + public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); + + /** + * Returns the value of 'test.timeout.factor' system property + * converted to {@code double}. + */ + public static final double TIMEOUT_FACTOR; + static { + String toFactor = System.getProperty("test.timeout.factor", "1.0"); + TIMEOUT_FACTOR = Double.parseDouble(toFactor); + } + + /** + * Returns the value of JTREG default test timeout in milliseconds + * converted to {@code long}. + */ + public static final long DEFAULT_TEST_TIMEOUT = TimeUnit.SECONDS.toMillis(120); + + private Utils() { + // Private constructor to prevent class instantiation + } + + /** + * Returns the list of VM options. + * + * @return List of VM options + */ + public static List getVmOptions() { + return Arrays.asList(safeSplitString(VM_OPTIONS)); + } + + /** + * Returns the list of VM options with -J prefix. + * + * @return The list of VM options with -J prefix + */ + public static List getForwardVmOptions() { + String[] opts = safeSplitString(VM_OPTIONS); + for (int i = 0; i < opts.length; i++) { + opts[i] = "-J" + opts[i]; + } + return Arrays.asList(opts); + } + + /** + * Returns the default JTReg arguments for a jvm running a test. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts. + * @return An array of options, or an empty array if no opptions. + */ + public static String[] getTestJavaOpts() { + List opts = new ArrayList(); + Collections.addAll(opts, safeSplitString(VM_OPTIONS)); + Collections.addAll(opts, safeSplitString(JAVA_OPTIONS)); + return opts.toArray(new String[0]); + } + + /** + * Combines given arguments with default JTReg arguments for a jvm running a test. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts + * @return The combination of JTReg test java options and user args. + */ + public static String[] addTestJavaOpts(String... userArgs) { + List opts = new ArrayList(); + Collections.addAll(opts, getTestJavaOpts()); + Collections.addAll(opts, userArgs); + return opts.toArray(new String[0]); + } + + /** + * Removes any options specifying which GC to use, for example "-XX:+UseG1GC". + * Removes any options matching: -XX:(+/-)Use*GC + * Used when a test need to set its own GC version. Then any + * GC specified by the framework must first be removed. + * @return A copy of given opts with all GC options removed. + */ + private static final Pattern useGcPattern = Pattern.compile( + "(?:\\-XX\\:[\\+\\-]Use.+GC)" + + "|(?:\\-Xconcgc)"); + public static List removeGcOpts(List opts) { + List optsWithoutGC = new ArrayList(); + for (String opt : opts) { + if (useGcPattern.matcher(opt).matches()) { + System.out.println("removeGcOpts: removed " + opt); + } else { + optsWithoutGC.add(opt); + } + } + return optsWithoutGC; + } + + /** + * Splits a string by white space. + * Works like String.split(), but returns an empty array + * if the string is null or empty. + */ + private static String[] safeSplitString(String s) { + if (s == null || s.trim().isEmpty()) { + return new String[] {}; + } + return s.trim().split("\\s+"); + } + + /** + * @return The full command line for the ProcessBuilder. + */ + public static String getCommandLine(ProcessBuilder pb) { + StringBuilder cmd = new StringBuilder(); + for (String s : pb.command()) { + cmd.append(s).append(" "); + } + return cmd.toString(); + } + + /** + * Returns the free port on the local host. + * The function will spin until a valid port number is found. + * + * @return The port number + * @throws InterruptedException if any thread has interrupted the current thread + * @throws IOException if an I/O error occurs when opening the socket + */ + public static int getFreePort() throws InterruptedException, IOException { + int port = -1; + + while (port <= 0) { + Thread.sleep(100); + + ServerSocket serverSocket = null; + try { + serverSocket = new ServerSocket(0); + port = serverSocket.getLocalPort(); + } finally { + serverSocket.close(); + } + } + + return port; + } + + /** + * Returns the name of the local host. + * + * @return The host name + * @throws UnknownHostException if IP address of a host could not be determined + */ + public static String getHostname() throws UnknownHostException { + InetAddress inetAddress = InetAddress.getLocalHost(); + String hostName = inetAddress.getHostName(); + + assertTrue((hostName != null && !hostName.isEmpty()), + "Cannot get hostname"); + + return hostName; + } + + /** + * Uses "jcmd -l" to search for a jvm pid. This function will wait + * forever (until jtreg timeout) for the pid to be found. + * @param key Regular expression to search for + * @return The found pid. + */ + public static int waitForJvmPid(String key) throws Throwable { + final long iterationSleepMillis = 250; + System.out.println("waitForJvmPid: Waiting for key '" + key + "'"); + System.out.flush(); + while (true) { + int pid = tryFindJvmPid(key); + if (pid >= 0) { + return pid; + } + Thread.sleep(iterationSleepMillis); + } + } + + /** + * Searches for a jvm pid in the output from "jcmd -l". + * + * Example output from jcmd is: + * 12498 sun.tools.jcmd.JCmd -l + * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar + * + * @param key A regular expression to search for. + * @return The found pid, or -1 if Enot found. + * @throws Exception If multiple matching jvms are found. + */ + public static int tryFindJvmPid(String key) throws Throwable { + OutputAnalyzer output = null; + try { + JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd"); + jcmdLauncher.addToolArg("-l"); + output = ProcessTools.executeProcess(jcmdLauncher.getCommand()); + output.shouldHaveExitValue(0); + + // Search for a line starting with numbers (pid), follwed by the key. + Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n"); + Matcher matcher = pattern.matcher(output.getStdout()); + + int pid = -1; + if (matcher.find()) { + pid = Integer.parseInt(matcher.group(1)); + System.out.println("findJvmPid.pid: " + pid); + if (matcher.find()) { + throw new Exception("Found multiple JVM pids for key: " + key); + } + } + return pid; + } catch (Throwable t) { + System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t)); + throw t; + } + } + + /** + * Adjusts the provided timeout value for the TIMEOUT_FACTOR + * @param tOut the timeout value to be adjusted + * @return The timeout value adjusted for the value of "test.timeout.factor" + * system property + */ + public static long adjustTimeout(long tOut) { + return Math.round(tOut * Utils.TIMEOUT_FACTOR); + } + + /** + * Wait for condition to be true + * + * @param condition, a condition to wait for + */ + public static final void waitForCondition(BooleanSupplier condition) { + waitForCondition(condition, -1L, 100L); + } + + /** + * Wait until timeout for condition to be true + * + * @param condition, a condition to wait for + * @param timeout a time in milliseconds to wait for condition to be true + * specifying -1 will wait forever + * @return condition value, to determine if wait was successfull + */ + public static final boolean waitForCondition(BooleanSupplier condition, + long timeout) { + return waitForCondition(condition, timeout, 100L); + } + + /** + * Wait until timeout for condition to be true for specified time + * + * @param condition, a condition to wait for + * @param timeout a time in milliseconds to wait for condition to be true, + * specifying -1 will wait forever + * @param sleepTime a time to sleep value in milliseconds + * @return condition value, to determine if wait was successfull + */ + public static final boolean waitForCondition(BooleanSupplier condition, + long timeout, long sleepTime) { + long startTime = System.currentTimeMillis(); + while (!(condition.getAsBoolean() || (timeout != -1L + && ((System.currentTimeMillis() - startTime) > timeout)))) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new Error(e); + } + } + return condition.getAsBoolean(); + } + + /** + * Interface same as java.lang.Runnable but with + * method {@code run()} able to throw any Throwable. + */ + public static interface ThrowingRunnable { + void run() throws Throwable; + } + + /** + * Filters out an exception that may be thrown by the given + * test according to the given filter. + * + * @param test - method that is invoked and checked for exception. + * @param filter - function that checks if the thrown exception matches + * criteria given in the filter's implementation. + * @return - exception that matches the filter if it has been thrown or + * {@code null} otherwise. + * @throws Throwable - if test has thrown an exception that does not + * match the filter. + */ + public static Throwable filterException(ThrowingRunnable test, + Function filter) throws Throwable { + try { + test.run(); + } catch (Throwable t) { + if (filter.apply(t)) { + return t; + } else { + throw t; + } + } + return null; + } +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/BasicModularXMLParserTest.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/BasicModularXMLParserTest.java new file mode 100644 index 00000000000..c3403f9d1d0 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/BasicModularXMLParserTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 static org.testng.Assert.assertTrue; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.testlibrary.ProcessTools.executeTestJava; +import jdk.testlibrary.CompilerUtils; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +/* + * @test + * @library /javax/xml/jaxp/libs + * @build jdk.testlibrary.* + * @run testng BasicModularXMLParserTest + * @bug 8078820 + * @summary Tests JAXP lib can instantiate the following interfaces + * with customized provider module on boot layer + * + * javax.xml.datatype.DatatypeFactory + * javax.xml.parsers.DocumentBuilderFactory + * javax.xml.parsers.SAXParserFactory + * javax.xml.stream.XMLEventFactory + * javax.xml.stream.XMLInputFactory + * javax.xml.stream.XMLOutputFactory + * javax.xml.transform.TransformerFactory + * javax.xml.validation.SchemaFactory + * javax.xml.xpath.XPathFactory + */ + +@Test +public class BasicModularXMLParserTest { + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MOD_DIR1 = Paths.get("mod1"); + private static final Path MOD_DIR2 = Paths.get("mod2"); + private static final Path CLASSES_DIR = Paths.get("classes"); + + /* + * Compiles all modules used by the test + */ + @BeforeTest + public void compileAll() throws Exception { + assertTrue(CompilerUtils.compile(SRC_DIR.resolve("xmlprovider1"), MOD_DIR1.resolve("xmlprovider1"))); + assertTrue(CompilerUtils.compile(SRC_DIR.resolve("xmlprovider2"), MOD_DIR2.resolve("xmlprovider2"))); + assertTrue(CompilerUtils.compile(SRC_DIR.resolve("unnamed"), CLASSES_DIR)); + } + + /* + * test the default JAXP implementation + */ + public void testDefault() throws Exception { + int exitValue + = executeTestJava("-cp", CLASSES_DIR.toString(), + "Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + /* + * test loading one provider module + */ + public void testWithOneProvider() throws Exception { + int exitValue + = executeTestJava("-mp", MOD_DIR1.toString(), + "-cp", CLASSES_DIR.toString(), + "Main", "xmlprovider1") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + /* + * test loading both provider modules + */ + public void testWithTwoProvider() throws Exception { + int exitValue + = executeTestJava("-mp", MOD_DIR1.toString() + File.pathSeparator + MOD_DIR2.toString(), + "-cp", CLASSES_DIR.toString(), + "Main", "xmlprovider1", "xmlprovider2") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/LayerModularXMLParserTest.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/LayerModularXMLParserTest.java new file mode 100644 index 00000000000..45f24001278 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/LayerModularXMLParserTest.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 static java.lang.module.ModuleFinder.empty; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.lang.ClassLoader; +import java.lang.String; +import java.lang.System; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Method; +import java.lang.reflect.Module; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Iterator; +import java.util.ServiceLoader; +import java.util.Set; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import jdk.testlibrary.CompilerUtils; + +/* + * @test + * @library /javax/xml/jaxp/libs + * @build jdk.testlibrary.* + * @run testng LayerModularXMLParserTest + * @bug 8078820 + * @summary Tests JAXP lib works with layer and TCCL + */ + +@Test +public class LayerModularXMLParserTest { + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MOD_DIR1 = Paths.get("mod1"); + private static final Path MOD_DIR2 = Paths.get("mod2"); + + /* + * services provided by provider1 + */ + private static final String[] services1 = { "javax.xml.parsers.DocumentBuilderFactory", + "javax.xml.parsers.SAXParserFactory", "javax.xml.stream.XMLInputFactory", + "javax.xml.stream.XMLOutputFactory", "javax.xml.transform.TransformerFactory", + "javax.xml.validation.SchemaFactory", "javax.xml.xpath.XPathFactory" }; + + /* + * services provided by provider2 + */ + private static final String[] services2 = { "javax.xml.datatype.DatatypeFactory", + "javax.xml.stream.XMLEventFactory" }; + + /* + * Compiles all modules used by the test + */ + @BeforeTest + public void compileAll() throws Exception { + assertTrue(CompilerUtils.compile(SRC_DIR.resolve("xmlprovider1"), MOD_DIR1.resolve("xmlprovider1"))); + assertTrue(CompilerUtils.compile(SRC_DIR.resolve("xmlprovider2"), MOD_DIR2.resolve("xmlprovider2"))); + assertTrue(CompilerUtils.compile(SRC_DIR.resolve("test"), MOD_DIR1.resolve("test"))); + assertTrue(CompilerUtils.compile(SRC_DIR.resolve("test"), MOD_DIR2.resolve("test"))); + } + + /* + * layer 1 is created on top of boot layer, layer1 includes module provider1. + * + * Instantiate each XML service, verify the services provided by provider1 + * are loaded from layer 1, the other services are loaded from boot layer + */ + public void testOneLayer() throws Exception { + ModuleFinder finder1 = ModuleFinder.of(MOD_DIR1); + Configuration cf1 = Layer.boot().configuration() + .resolveRequiresAndUses(finder1, empty(), Set.of("test")); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, scl); + ClassLoader cl1 = layer1.findLoader("test"); + + Method m = cl1.loadClass("test.XMLFactoryHelper").getMethod("instantiateXMLService", String.class); + for (String service : services1) { + Object o = m.invoke(null, service); + Layer providerLayer = o.getClass().getModule().getLayer(); + assertSame(providerLayer, layer1); + } + + for (String service : services2) { + Object o = m.invoke(null, service); + Layer providerLayer = o.getClass().getModule().getLayer(); + assertSame(providerLayer, Layer.boot()); + } + + } + + /* + * layer 1 is created on top of boot layer, layer 1 includes module provider1. + * layer 2 is created on top of layer 1, layer 2 includes module provider2. + * + * Instantiate each XML service, verify the services provided by provider1 + * are loaded from layer 1, the services provided by provider2 are loaded from layer 2 + */ + public void testTwoLayer() throws Exception { + ModuleFinder finder1 = ModuleFinder.of(MOD_DIR1); + Configuration cf1 = Layer.boot().configuration() + .resolveRequiresAndUses(finder1, empty(), Set.of("test")); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, scl); + + ModuleFinder finder2 = ModuleFinder.of(MOD_DIR2); + Configuration cf2 = cf1.resolveRequiresAndUses(finder2, empty(), Set.of("test")); + Layer layer2 = layer1.defineModulesWithOneLoader(cf2, layer1.findLoader("test")); + ClassLoader cl2 = layer2.findLoader("test"); + + Method m = cl2.loadClass("test.XMLFactoryHelper").getMethod("instantiateXMLService", String.class); + for (String service : services1) { + Object o = m.invoke(null, service); + Layer providerLayer = o.getClass().getModule().getLayer(); + assertSame(providerLayer, layer1); + } + + for (String service : services2) { + Object o = m.invoke(null, service); + Layer providerLayer = o.getClass().getModule().getLayer(); + assertSame(providerLayer, layer2); + } + + } + + /* + * layer 1 is created on top of boot layer, layer 1 includes module provider1 and provider2. + * layer 2 is created on top of layer 1, layer 2 includes module provider2. + * + * Instantiate each XML service, verify the services provided by provider1 + * are loaded from layer 1, the services provided by provider2 are loaded from layer 2 + */ + public void testTwoLayerWithDuplicate() throws Exception { + ModuleFinder finder1 = ModuleFinder.of(MOD_DIR1, MOD_DIR2); + Configuration cf1 = Layer.boot().configuration() + .resolveRequiresAndUses(finder1, empty(), Set.of("test")); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, scl); + + ModuleFinder finder2 = ModuleFinder.of(MOD_DIR2); + Configuration cf2 = cf1.resolveRequiresAndUses(finder2, empty(), Set.of("test")); + Layer layer2 = layer1.defineModulesWithOneLoader(cf2, layer1.findLoader("test")); + ClassLoader cl2 = layer2.findLoader("test"); + + Method m = cl2.loadClass("test.XMLFactoryHelper").getMethod("instantiateXMLService", String.class); + for (String service : services1) { + Object o = m.invoke(null, service); + Layer providerLayer = o.getClass().getModule().getLayer(); + assertSame(providerLayer, layer1); + } + + for (String service : services2) { + Object o = m.invoke(null, service); + Layer providerLayer = o.getClass().getModule().getLayer(); + assertSame(providerLayer, layer2); + } + + } +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/module-info.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/module-info.java new file mode 100644 index 00000000000..9a1caa4e1f9 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/module-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module test { + requires java.xml; + exports test; +} \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/test/XMLFactoryHelper.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/test/XMLFactoryHelper.java new file mode 100644 index 00000000000..6dfaec5cedf --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/test/XMLFactoryHelper.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; + +import java.lang.Class; +import java.lang.String; +import java.lang.System; +import java.util.Iterator; +import java.util.ServiceLoader; + +public class XMLFactoryHelper { + /* + * instantiate a xml factory by reflection e.g. + * DocumentBuilderFactory.newInstance() + */ + public static Object instantiateXMLService(String serviceName) throws Exception { + ClassLoader backup = Thread.currentThread().getContextClassLoader(); + try { + // set thread context class loader to module class loader + Thread.currentThread().setContextClassLoader(XMLFactoryHelper.class.getClassLoader()); + if (serviceName.equals("javax.xml.validation.SchemaFactory")) + return Class.forName(serviceName).getMethod("newInstance", String.class) + .invoke(null, W3C_XML_SCHEMA_NS_URI); + else + return Class.forName(serviceName).getMethod("newInstance").invoke(null); + } finally { + Thread.currentThread().setContextClassLoader(backup); + } + + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/unnamed/Main.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/unnamed/Main.java new file mode 100644 index 00000000000..cb0a37e916b --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/unnamed/Main.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; + +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; + +public class Main { + /* + * @param args, the names of provider modules, which have been loaded + */ + public static void main(String[] args) throws Exception { + Module xml = Layer.boot().findModule("java.xml").get(); + + Set allServices = new HashSet<>(Arrays.asList(expectedAllServices)); + if (!allServices.equals(xml.getDescriptor().uses())) + throw new AssertionError("Expect xml module uses: " + allServices + " But actually uses: " + + xml.getDescriptor().uses()); + + long violationCount = Stream.of(args) + .map(xmlProviderName -> Layer.boot().findModule(xmlProviderName).get()) + .mapToLong( + // services provided by the implementation in provider module + provider -> provider.getDescriptor().provides().keySet().stream() + .filter(serviceName -> { + allServices.remove(serviceName); // remove service provided by + // customized module from allServices + return !belongToModule(serviceName, instantiateXMLService(serviceName), provider); + }).count()) + .sum(); + + // the remaining services should be provided by the default implementation + violationCount += allServices.stream() + .filter(serviceName -> !belongToModule(serviceName, instantiateXMLService(serviceName), xml)) + .count(); + + if (violationCount > 0) + throw new AssertionError(violationCount + " services are not provided by expected module"); + } + + /* + * instantiate a xml factory by reflection e.g. + * DocumentBuilderFactory.newInstance() + */ + private static Object instantiateXMLService(String serviceName) { + try { + if (serviceName.equals("javax.xml.validation.SchemaFactory")) + return Class.forName(serviceName).getMethod("newInstance", String.class) + .invoke(null, W3C_XML_SCHEMA_NS_URI); + else + return Class.forName(serviceName).getMethod("newInstance").invoke(null); + } catch (Exception e) { + e.printStackTrace(System.err); + throw new RuntimeException(e); + } + } + + /* + * verify which module provides the xml factory + */ + private static boolean belongToModule(String factoryName, Object factory, Module expected) { + Module actual = factory.getClass().getModule(); + if (!actual.equals(expected)) { + System.err.println("Expect " + factoryName + " is provided by " + expected + + ", but actual implementation " + factory.getClass() + " is provided by " + actual); + return false; + } else { + System.out.println(factory.getClass() + " is provided by " + expected); + return true; + } + } + + /* + * This list equals the declarations in java.xml module-info.java + */ + private static final String[] expectedAllServices = { "javax.xml.datatype.DatatypeFactory", + "javax.xml.parsers.DocumentBuilderFactory", "javax.xml.parsers.SAXParserFactory", + "javax.xml.stream.XMLEventFactory", "javax.xml.stream.XMLInputFactory", + "javax.xml.stream.XMLOutputFactory", "javax.xml.transform.TransformerFactory", + "javax.xml.validation.SchemaFactory", "javax.xml.xpath.XPathFactory" }; + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/module-info.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/module-info.java new file mode 100644 index 00000000000..5a5b1b01447 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/module-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module xmlprovider1 { + requires java.xml; + + provides javax.xml.parsers.DocumentBuilderFactory with xp1.DocumentBuilderFactoryImpl; + provides javax.xml.parsers.SAXParserFactory with xp1.SAXParserFactoryImpl; + provides javax.xml.stream.XMLInputFactory with xp1.XMLInputFactoryImpl; + provides javax.xml.stream.XMLOutputFactory with xp1.XMLOutputFactoryImpl; + provides javax.xml.transform.TransformerFactory with xp1.TransformerFactoryImpl; + provides javax.xml.validation.SchemaFactory with xp1.SchemaFactoryImpl; + provides javax.xml.xpath.XPathFactory with xp1.XPathFactoryImpl; +} \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/DocumentBuilderFactoryImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/DocumentBuilderFactoryImpl.java new file mode 100644 index 00000000000..7e302b9630c --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/DocumentBuilderFactoryImpl.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package xp1; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory { + + @Override + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + return null; + } + + @Override + public void setAttribute(String name, Object value) throws IllegalArgumentException { + + } + + @Override + public Object getAttribute(String name) throws IllegalArgumentException { + return null; + } + + @Override + public void setFeature(String name, boolean value) throws ParserConfigurationException { + + } + + @Override + public boolean getFeature(String name) throws ParserConfigurationException { + return false; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/SAXParserFactoryImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/SAXParserFactoryImpl.java new file mode 100644 index 00000000000..5d4ce0602f3 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/SAXParserFactoryImpl.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package xp1; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +public class SAXParserFactoryImpl extends SAXParserFactory { + + @Override + public SAXParser newSAXParser() throws ParserConfigurationException, SAXException { + return null; + } + + @Override + public void setFeature(String name, boolean value) throws ParserConfigurationException, + SAXNotRecognizedException, SAXNotSupportedException { + + } + + @Override + public boolean getFeature(String name) throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException { + return false; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/SchemaFactoryImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/SchemaFactoryImpl.java new file mode 100644 index 00000000000..ca0cb3be8c7 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/SchemaFactoryImpl.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package xp1; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; + +import javax.xml.transform.Source; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; + +public class SchemaFactoryImpl extends SchemaFactory { + + @Override + public boolean isSchemaLanguageSupported(String schemaLanguage) { + // must be true, otherwise JAXP library will deny this impl + if (schemaLanguage.equals(W3C_XML_SCHEMA_NS_URI)) + return true; + else + return false; + } + + @Override + public void setErrorHandler(ErrorHandler errorHandler) { + + } + + @Override + public ErrorHandler getErrorHandler() { + return null; + } + + @Override + public void setResourceResolver(LSResourceResolver resourceResolver) { + + } + + @Override + public LSResourceResolver getResourceResolver() { + return null; + } + + @Override + public Schema newSchema(Source[] schemas) throws SAXException { + return null; + } + + @Override + public Schema newSchema() throws SAXException { + return null; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/TransformerFactoryImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/TransformerFactoryImpl.java new file mode 100644 index 00000000000..0feabb6b21f --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/TransformerFactoryImpl.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package xp1; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.URIResolver; + +public class TransformerFactoryImpl extends TransformerFactory { + + @Override + public Transformer newTransformer(Source source) throws TransformerConfigurationException { + return null; + } + + @Override + public Transformer newTransformer() throws TransformerConfigurationException { + return null; + } + + @Override + public Templates newTemplates(Source source) throws TransformerConfigurationException { + return null; + } + + @Override + public Source getAssociatedStylesheet(Source source, String media, String title, String charset) + throws TransformerConfigurationException { + return null; + } + + @Override + public void setURIResolver(URIResolver resolver) { + + } + + @Override + public URIResolver getURIResolver() { + return null; + } + + @Override + public void setFeature(String name, boolean value) throws TransformerConfigurationException { + + } + + @Override + public boolean getFeature(String name) { + return false; + } + + @Override + public void setAttribute(String name, Object value) { + + } + + @Override + public Object getAttribute(String name) { + return null; + } + + @Override + public void setErrorListener(ErrorListener listener) { + + } + + @Override + public ErrorListener getErrorListener() { + return null; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XMLInputFactoryImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XMLInputFactoryImpl.java new file mode 100644 index 00000000000..de4f6cbe075 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XMLInputFactoryImpl.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package xp1; + +import java.io.InputStream; +import java.io.Reader; + +import javax.xml.stream.EventFilter; +import javax.xml.stream.StreamFilter; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLReporter; +import javax.xml.stream.XMLResolver; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.util.XMLEventAllocator; +import javax.xml.transform.Source; + +public class XMLInputFactoryImpl extends XMLInputFactory { + + @Override + public XMLStreamReader createXMLStreamReader(Reader reader) throws XMLStreamException { + return null; + } + + @Override + public XMLStreamReader createXMLStreamReader(Source source) throws XMLStreamException { + return null; + } + + @Override + public XMLStreamReader createXMLStreamReader(InputStream stream) throws XMLStreamException { + return null; + } + + @Override + public XMLStreamReader createXMLStreamReader(InputStream stream, String encoding) + throws XMLStreamException { + return null; + } + + @Override + public XMLStreamReader createXMLStreamReader(String systemId, InputStream stream) + throws XMLStreamException { + return null; + } + + @Override + public XMLStreamReader createXMLStreamReader(String systemId, Reader reader) throws XMLStreamException { + return null; + } + + @Override + public XMLEventReader createXMLEventReader(Reader reader) throws XMLStreamException { + return null; + } + + @Override + public XMLEventReader createXMLEventReader(String systemId, Reader reader) throws XMLStreamException { + return null; + } + + @Override + public XMLEventReader createXMLEventReader(XMLStreamReader reader) throws XMLStreamException { + return null; + } + + @Override + public XMLEventReader createXMLEventReader(Source source) throws XMLStreamException { + return null; + } + + @Override + public XMLEventReader createXMLEventReader(InputStream stream) throws XMLStreamException { + return null; + } + + @Override + public XMLEventReader createXMLEventReader(InputStream stream, String encoding) throws XMLStreamException { + return null; + } + + @Override + public XMLEventReader createXMLEventReader(String systemId, InputStream stream) throws XMLStreamException { + return null; + } + + @Override + public XMLStreamReader createFilteredReader(XMLStreamReader reader, StreamFilter filter) + throws XMLStreamException { + return null; + } + + @Override + public XMLEventReader createFilteredReader(XMLEventReader reader, EventFilter filter) + throws XMLStreamException { + return null; + } + + @Override + public XMLResolver getXMLResolver() { + return null; + } + + @Override + public void setXMLResolver(XMLResolver resolver) { + + } + + @Override + public XMLReporter getXMLReporter() { + return null; + } + + @Override + public void setXMLReporter(XMLReporter reporter) { + + } + + @Override + public void setProperty(String name, Object value) throws IllegalArgumentException { + + } + + @Override + public Object getProperty(String name) throws IllegalArgumentException { + return null; + } + + @Override + public boolean isPropertySupported(String name) { + return false; + } + + @Override + public void setEventAllocator(XMLEventAllocator allocator) { + + } + + @Override + public XMLEventAllocator getEventAllocator() { + return null; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XMLOutputFactoryImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XMLOutputFactoryImpl.java new file mode 100644 index 00000000000..7042ca1af60 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XMLOutputFactoryImpl.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package xp1; + +import java.io.OutputStream; +import java.io.Writer; + +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; + +public class XMLOutputFactoryImpl extends XMLOutputFactory { + + @Override + public XMLStreamWriter createXMLStreamWriter(Writer stream) throws XMLStreamException { + return null; + } + + @Override + public XMLStreamWriter createXMLStreamWriter(OutputStream stream) throws XMLStreamException { + return null; + } + + @Override + public XMLStreamWriter createXMLStreamWriter(OutputStream stream, String encoding) + throws XMLStreamException { + return null; + } + + @Override + public XMLStreamWriter createXMLStreamWriter(Result result) throws XMLStreamException { + return null; + } + + @Override + public XMLEventWriter createXMLEventWriter(Result result) throws XMLStreamException { + return null; + } + + @Override + public XMLEventWriter createXMLEventWriter(OutputStream stream) throws XMLStreamException { + return null; + } + + @Override + public XMLEventWriter createXMLEventWriter(OutputStream stream, String encoding) + throws XMLStreamException { + return null; + } + + @Override + public XMLEventWriter createXMLEventWriter(Writer stream) throws XMLStreamException { + return null; + } + + @Override + public void setProperty(String name, Object value) throws IllegalArgumentException { + + } + + @Override + public Object getProperty(String name) throws IllegalArgumentException { + return null; + } + + @Override + public boolean isPropertySupported(String name) { + return false; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XPathFactoryImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XPathFactoryImpl.java new file mode 100644 index 00000000000..bf5aa7aa20e --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider1/xp1/XPathFactoryImpl.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package xp1; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; +import javax.xml.xpath.XPathFactoryConfigurationException; +import javax.xml.xpath.XPathFunctionResolver; +import javax.xml.xpath.XPathVariableResolver; + +public class XPathFactoryImpl extends XPathFactory { + + @Override + public boolean isObjectModelSupported(String objectModel) { + // must be true, otherwise JAXP library will deny this impl + return true; + } + + @Override + public void setFeature(String name, boolean value) throws XPathFactoryConfigurationException { + + } + + @Override + public boolean getFeature(String name) throws XPathFactoryConfigurationException { + return false; + } + + @Override + public void setXPathVariableResolver(XPathVariableResolver resolver) { + + } + + @Override + public void setXPathFunctionResolver(XPathFunctionResolver resolver) { + + } + + @Override + public XPath newXPath() { + return null; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/module-info.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/module-info.java new file mode 100644 index 00000000000..d55645e58e9 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/module-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module xmlprovider2 { + requires java.xml; + + provides javax.xml.datatype.DatatypeFactory with xp2.DatatypeFactoryImpl; + provides javax.xml.stream.XMLEventFactory with xp2.XMLEventFactoryImpl; +} \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/DatatypeFactoryImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/DatatypeFactoryImpl.java new file mode 100644 index 00000000000..e4a38886dcc --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/DatatypeFactoryImpl.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package xp2; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.GregorianCalendar; + +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; + +public class DatatypeFactoryImpl extends DatatypeFactory { + + @Override + public Duration newDuration(String lexicalRepresentation) { + return null; + } + + @Override + public Duration newDuration(long durationInMilliSeconds) { + return null; + } + + @Override + public Duration newDuration(boolean isPositive, BigInteger years, BigInteger months, BigInteger days, + BigInteger hours, BigInteger minutes, BigDecimal seconds) { + return null; + } + + @Override + public XMLGregorianCalendar newXMLGregorianCalendar() { + return null; + } + + @Override + public XMLGregorianCalendar newXMLGregorianCalendar(String lexicalRepresentation) { + return null; + } + + @Override + public XMLGregorianCalendar newXMLGregorianCalendar(GregorianCalendar cal) { + return null; + } + + @Override + public XMLGregorianCalendar newXMLGregorianCalendar(BigInteger year, int month, int day, int hour, + int minute, int second, BigDecimal fractionalSecond, int timezone) { + return null; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/XMLEventFactoryImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/XMLEventFactoryImpl.java new file mode 100644 index 00000000000..e4e89c8383b --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/XMLEventFactoryImpl.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package xp2; + +import java.util.Iterator; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.Comment; +import javax.xml.stream.events.DTD; +import javax.xml.stream.events.EndDocument; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.EntityReference; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartDocument; +import javax.xml.stream.events.StartElement; + +public class XMLEventFactoryImpl extends XMLEventFactory { + + @Override + public void setLocation(Location location) { + + } + + @Override + public Attribute createAttribute(String prefix, String namespaceURI, String localName, String value) { + return null; + } + + @Override + public Attribute createAttribute(String localName, String value) { + return null; + } + + @Override + public Attribute createAttribute(QName name, String value) { + return null; + } + + @Override + public Namespace createNamespace(String namespaceURI) { + return null; + } + + @Override + public Namespace createNamespace(String prefix, String namespaceUri) { + return null; + } + + @Override + public StartElement createStartElement(QName name, Iterator attributes, Iterator namespaces) { + return null; + } + + @Override + public StartElement createStartElement(String prefix, String namespaceUri, String localName) { + return null; + } + + @Override + public StartElement createStartElement(String prefix, String namespaceUri, String localName, + Iterator attributes, Iterator namespaces) { + return null; + } + + @Override + public StartElement createStartElement(String prefix, String namespaceUri, String localName, + Iterator attributes, Iterator namespaces, NamespaceContext context) { + return null; + } + + @Override + public EndElement createEndElement(QName name, Iterator namespaces) { + return null; + } + + @Override + public EndElement createEndElement(String prefix, String namespaceUri, String localName) { + return null; + } + + @Override + public EndElement createEndElement(String prefix, String namespaceUri, String localName, + Iterator namespaces) { + return null; + } + + @Override + public Characters createCharacters(String content) { + return null; + } + + @Override + public Characters createCData(String content) { + return null; + } + + @Override + public Characters createSpace(String content) { + return null; + } + + @Override + public Characters createIgnorableSpace(String content) { + return null; + } + + @Override + public StartDocument createStartDocument() { + return null; + } + + @Override + public StartDocument createStartDocument(String encoding, String version, boolean standalone) { + return null; + } + + @Override + public StartDocument createStartDocument(String encoding, String version) { + return null; + } + + @Override + public StartDocument createStartDocument(String encoding) { + return null; + } + + @Override + public EndDocument createEndDocument() { + return null; + } + + @Override + public EntityReference createEntityReference(String name, EntityDeclaration declaration) { + return null; + } + + @Override + public Comment createComment(String text) { + return null; + } + + @Override + public ProcessingInstruction createProcessingInstruction(String target, String data) { + return null; + } + + @Override + public DTD createDTD(String dtd) { + return null; + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/TEST.properties b/jaxp/test/javax/xml/jaxp/module/TEST.properties new file mode 100644 index 00000000000..85a3ae5f5c7 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/TEST.properties @@ -0,0 +1,5 @@ +# Tests that must run in othervm mode +othervm.dirs= . + +# Declare module dependency +modules=java.xml From 187b51a62cbdb386f263fbbe7ef74f20d514ffb0 Mon Sep 17 00:00:00 2001 From: Felix Yang Date: Wed, 20 Apr 2016 00:35:02 -0700 Subject: [PATCH 114/222] 8154543: NetworkInterfaceStreamTest.java fails intermittently after JDK-8146758 Reviewed-by: chegar --- .../java/net/NetworkInterface/NetworkInterfaceStreamTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java index 08075ac7472..1fa3a557941 100644 --- a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java +++ b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java @@ -51,7 +51,8 @@ public class NetworkInterfaceStreamTest extends OpTestCase { public void testNetworkInterfaces() throws SocketException { Supplier> ss = () -> { try { - return allNetworkInterfaces(); + return NetworkInterface.networkInterfaces() + .filter(ni -> isIncluded(ni)); } catch (SocketException e) { throw new RuntimeException(e); From 611a14587e919590c6609a2c3ae419978a3747d9 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 20 Apr 2016 16:47:12 +0100 Subject: [PATCH 115/222] 8154707: java/util/ServiceLoader/modules/BasicTest.java failing Reviewed-by: chegar --- .../modules/{BasicTest.java => MiscTests.java} | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) rename jdk/test/java/util/ServiceLoader/modules/{BasicTest.java => MiscTests.java} (82%) diff --git a/jdk/test/java/util/ServiceLoader/modules/BasicTest.java b/jdk/test/java/util/ServiceLoader/modules/MiscTests.java similarity index 82% rename from jdk/test/java/util/ServiceLoader/modules/BasicTest.java rename to jdk/test/java/util/ServiceLoader/modules/MiscTests.java index 3b64a1d7d9a..5a99a30737c 100644 --- a/jdk/test/java/util/ServiceLoader/modules/BasicTest.java +++ b/jdk/test/java/util/ServiceLoader/modules/MiscTests.java @@ -30,11 +30,11 @@ import static org.testng.Assert.*; /* * @test - * @run testng BasicTest + * @run testng MiscTests * @summary Basic test of ServiceLoader with modules */ -public class BasicTest { +public class MiscTests { @Test public void testEmptyLayer() { @@ -43,18 +43,6 @@ public class BasicTest { assertFalse(sl.iterator().hasNext()); } - @Test - public void testBootLayer() { - ServiceLoader sl - = ServiceLoader.load(Layer.boot(), Provider.class); - boolean found = false; - for (Provider provider : sl) { - if (provider.getName().equals("SunJCE")) - found = true; - } - assertTrue(found); - } - @Test(expectedExceptions = { NullPointerException.class }) public void testNullLayer() { ServiceLoader.load(null, Provider.class); From f69b5f55eb71737d3afe966f56e364e26b3bc1e7 Mon Sep 17 00:00:00 2001 From: Peter Brunet Date: Wed, 20 Apr 2016 12:23:38 -0500 Subject: [PATCH 116/222] 8076554: [macosx] Custom Swing text components need to allow standard accessibility Remove JTextComponent listeners; use property change listeners for caret/text Reviewed-by: prr, alexsch --- .../macosx/AccessibilityEventMonitor.java | 253 ++++++++++++++++++ .../classes/sun/lwawt/macosx/CAccessible.java | 47 ++-- 2 files changed, 271 insertions(+), 29 deletions(-) create mode 100644 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/AccessibilityEventMonitor.java diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/AccessibilityEventMonitor.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/AccessibilityEventMonitor.java new file mode 100644 index 00000000000..c575590802b --- /dev/null +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/AccessibilityEventMonitor.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.lwawt.macosx; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.swing.event.EventListenerList; + +/** + *

    {@code AccessibilityEventMonitor} implements a PropertyChange listener + * on every UI object that implements interface {@code Accessible} in the Java + * Virtual Machine. The events captured by these listeners are made available + * through listeners supported by {@code AccessibilityEventMonitor}. + * With this, all the individual events on each of the UI object + * instances are funneled into one set of PropertyChange listeners. + * + * This code is a subset of com.sun.java.accessibility.util.AccessibilityEventMonitor + * which resides in module jdk.accessibility. Due to modularization the code in + * this package, java.desktop, can not be dependent on code in jdk.accessibility. + */ + +class AccessibilityEventMonitor { + + /** + * The current list of registered {@link java.beans.PropertyChangeListener + * PropertyChangeListener} classes. + * + * @see #addPropertyChangeListener + */ + private static final EventListenerList listenerList = + new EventListenerList(); + + + /** + * The actual listener that is installed on the component instances. + * This listener calls the other registered listeners when an event + * occurs. By doing things this way, the actual number of listeners + * installed on a component instance is drastically reduced. + */ + private static final AccessibilityEventListener accessibilityListener = + new AccessibilityEventListener(); + + /** + * Adds the specified listener to receive all PropertyChange events on + * each UI object instance in the Java Virtual Machine as they occur. + *

    Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to UI object instances that support this listener type. + * + * @param l the listener to add + * @param a the Accessible object to add the PropertyChangeListener to + */ + + static void addPropertyChangeListener(PropertyChangeListener l, Accessible a) { + if (listenerList.getListenerCount(PropertyChangeListener.class) == 0) { + accessibilityListener.installListeners(a); + } + listenerList.add(PropertyChangeListener.class, l); + } + + /** + * AccessibilityEventListener is the class that does all the work for + * AccessibilityEventMonitor. It is not intended for use by any other + * class except AccessibilityEventMonitor. + */ + + private static class AccessibilityEventListener implements PropertyChangeListener { + + /** + * Installs PropertyChange listeners to the Accessible object, and its + * children (so long as the object isn't of TRANSIENT state). + * + * @param a the Accessible object to add listeners to + */ + private void installListeners(Accessible a) { + installListeners(a.getAccessibleContext()); + } + + /** + * Installs PropertyChange listeners to the AccessibleContext object, + * and its * children (so long as the object isn't of TRANSIENT state). + * + * @param ac the AccessibleContext to add listeners to + */ + private void installListeners(AccessibleContext ac) { + + if (ac != null) { + AccessibleStateSet states = ac.getAccessibleStateSet(); + if (!states.contains(AccessibleState.TRANSIENT)) { + ac.addPropertyChangeListener(this); + /* + * Don't add listeners to transient children. Components + * with transient children should return an AccessibleStateSet + * containing AccessibleState.MANAGES_DESCENDANTS. Components + * may not explicitly return the MANAGES_DESCENDANTS state. + * In this case, don't add listeners to the children of + * lists, tables and trees. + */ + AccessibleStateSet set = ac.getAccessibleStateSet(); + if (set.contains(AccessibleState.MANAGES_DESCENDANTS)) { + return; + } + AccessibleRole role = ac.getAccessibleRole(); + if ( role == AccessibleRole.LIST || + role == AccessibleRole.TREE ) { + return; + } + if (role == AccessibleRole.TABLE) { + // handle Oracle tables containing tables + Accessible child = ac.getAccessibleChild(0); + if (child != null) { + AccessibleContext ac2 = child.getAccessibleContext(); + if (ac2 != null) { + role = ac2.getAccessibleRole(); + if (role != null && role != AccessibleRole.TABLE) { + return; + } + } + } + } + int count = ac.getAccessibleChildrenCount(); + for (int i = 0; i < count; i++) { + Accessible child = ac.getAccessibleChild(i); + if (child != null) { + installListeners(child); + } + } + } + } + } + + /** + * Removes PropertyChange listeners for the given Accessible object, + * its children (so long as the object isn't of TRANSIENT state). + * + * @param a the Accessible object to remove listeners from + */ + private void removeListeners(Accessible a) { + removeListeners(a.getAccessibleContext()); + } + + /** + * Removes PropertyChange listeners for the given AccessibleContext + * object, its children (so long as the object isn't of TRANSIENT + * state). + * + * @param a the Accessible object to remove listeners from + */ + private void removeListeners(AccessibleContext ac) { + + if (ac != null) { + // Listeners are not added to transient components. + AccessibleStateSet states = ac.getAccessibleStateSet(); + if (!states.contains(AccessibleState.TRANSIENT)) { + ac.removePropertyChangeListener(this); + /* + * Listeners are not added to transient children. Components + * with transient children should return an AccessibleStateSet + * containing AccessibleState.MANAGES_DESCENDANTS. Components + * may not explicitly return the MANAGES_DESCENDANTS state. + * In this case, don't remove listeners from the children of + * lists, tables and trees. + */ + if (states.contains(AccessibleState.MANAGES_DESCENDANTS)) { + return; + } + AccessibleRole role = ac.getAccessibleRole(); + if ( role == AccessibleRole.LIST || + role == AccessibleRole.TABLE || + role == AccessibleRole.TREE ) { + return; + } + int count = ac.getAccessibleChildrenCount(); + for (int i = 0; i < count; i++) { + Accessible child = ac.getAccessibleChild(i); + if (child != null) { + removeListeners(child); + } + } + } + } + } + + @Override + public void propertyChange(PropertyChangeEvent e) { + // propogate the event + Object[] listeners = + AccessibilityEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==PropertyChangeListener.class) { + ((PropertyChangeListener)listeners[i+1]).propertyChange(e); + } + } + + // handle childbirth/death + String name = e.getPropertyName(); + if (name.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) { + Object oldValue = e.getOldValue(); + Object newValue = e.getNewValue(); + + if ((oldValue == null) ^ (newValue == null)) { // one null, not both + if (oldValue != null) { + // this Accessible is a child that's going away + if (oldValue instanceof Accessible) { + Accessible a = (Accessible) oldValue; + removeListeners(a.getAccessibleContext()); + } else if (oldValue instanceof AccessibleContext) { + removeListeners((AccessibleContext) oldValue); + } + } else if (newValue != null) { + // this Accessible is a child was just born + if (newValue instanceof Accessible) { + Accessible a = (Accessible) newValue; + installListeners(a.getAccessibleContext()); + } else if (newValue instanceof AccessibleContext) { + installListeners((AccessibleContext) newValue); + } + } + } else { + System.out.println("ERROR in usage of PropertyChangeEvents for: " + e.toString()); + } + } + } + } +} diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java index c5611c4d453..20ce3551d94 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * 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,20 +26,18 @@ package sun.lwawt.macosx; import java.awt.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.lang.reflect.Field; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.swing.JProgressBar; import javax.swing.JSlider; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.text.JTextComponent; +import sun.lwawt.macosx.CFRetainedResource; class CAccessible extends CFRetainedResource implements Accessible { static Field getNativeAXResourceField() { @@ -99,13 +97,10 @@ class CAccessible extends CFRetainedResource implements Accessible { return accessible.getAccessibleContext(); } - // currently only supports text components public void addNotificationListeners(Component c) { - if (c instanceof JTextComponent) { - JTextComponent tc = (JTextComponent) c; - AXTextChangeNotifier listener = new AXTextChangeNotifier(); - tc.getDocument().addDocumentListener(listener); - tc.addCaretListener(listener); + AXTextChangeNotifier listener = new AXTextChangeNotifier(); + if (c instanceof Accessible) { + AccessibilityEventMonitor.addPropertyChangeListener(listener, (Accessible)c); } if (c instanceof JProgressBar) { JProgressBar pb = (JProgressBar) c; @@ -117,29 +112,23 @@ class CAccessible extends CFRetainedResource implements Accessible { } - private class AXTextChangeNotifier implements DocumentListener, CaretListener { - @Override - public void changedUpdate(DocumentEvent e) { - if (ptr != 0) valueChanged(ptr); - } + private class AXTextChangeNotifier implements PropertyChangeListener { @Override - public void insertUpdate(DocumentEvent e) { - if (ptr != 0) valueChanged(ptr); - } - - @Override - public void removeUpdate(DocumentEvent e) { - if (ptr != 0) valueChanged(ptr); - } - - @Override - public void caretUpdate(CaretEvent e) { - if (ptr != 0) selectionChanged(ptr); + public void propertyChange(PropertyChangeEvent e) { + String name = e.getPropertyName(); + if ( ptr != 0 ) { + if (name.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) { + selectionChanged(ptr); + } else if (name.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0 ) { + valueChanged(ptr); + } + } } } private class AXProgressChangeNotifier implements ChangeListener { + @Override public void stateChanged(ChangeEvent e) { if (ptr != 0) valueChanged(ptr); } From 29fc25717aa618bb32b0da5bc255d4a9b4018055 Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Wed, 20 Apr 2016 22:46:47 +0100 Subject: [PATCH 117/222] 8071125: Improve exception messages in URLPermission Reviewed-by: chegar, prappo --- .../share/classes/java/net/URLPermission.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/net/URLPermission.java b/jdk/src/java.base/share/classes/java/net/URLPermission.java index 78373e1087f..e188c81d73b 100644 --- a/jdk/src/java.base/share/classes/java/net/URLPermission.java +++ b/jdk/src/java.base/share/classes/java/net/URLPermission.java @@ -170,7 +170,8 @@ public final class URLPermission extends Permission { parseURI(getName()); int colon = actions.indexOf(':'); if (actions.lastIndexOf(':') != colon) { - throw new IllegalArgumentException("invalid actions string"); + throw new IllegalArgumentException( + "Invalid actions string: \"" + actions + "\""); } String methods, headers; @@ -371,7 +372,8 @@ public final class URLPermission extends Permission { l.add(s); b = new StringBuilder(); } else if (c == ' ' || c == '\t') { - throw new IllegalArgumentException("white space not allowed"); + throw new IllegalArgumentException( + "White space not allowed in methods: \"" + methods + "\""); } else { if (c >= 'a' && c <= 'z') { c += 'A' - 'a'; @@ -398,7 +400,8 @@ public final class URLPermission extends Permission { } b.append(c); } else if (c == ' ' || c == '\t') { - throw new IllegalArgumentException("white space not allowed"); + throw new IllegalArgumentException( + "White space not allowed in headers: \"" + headers + "\""); } else if (c == '-') { capitalizeNext = true; b.append(c); @@ -423,14 +426,16 @@ public final class URLPermission extends Permission { int len = url.length(); int delim = url.indexOf(':'); if (delim == -1 || delim + 1 == len) { - throw new IllegalArgumentException("invalid URL string"); + throw new IllegalArgumentException( + "Invalid URL string: \"" + url + "\""); } scheme = url.substring(0, delim).toLowerCase(); this.ssp = url.substring(delim + 1); if (!ssp.startsWith("//")) { if (!ssp.equals("*")) { - throw new IllegalArgumentException("invalid URL string"); + throw new IllegalArgumentException( + "Invalid URL string: \"" + url + "\""); } this.authority = new Authority(scheme, "*"); return; From 6e3d77a8bacc227b4bfbdab0ec4c23f02adf92cd Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 20 Apr 2016 15:06:13 -0700 Subject: [PATCH 118/222] 8154183: (spec) Spec of read(byte[],int,int) and readFully(byte[],int,int) is confusing/incomplete Clarify and expand specification of ObjectInputStream.read(byte[],int,int) and both variants of {DataInput,DataInputStream,ObjectInputStream,RandomAccessfile}.readFully(). Reviewed-by: rriggs, smarks --- .../share/classes/java/io/DataInput.java | 27 ++++++++------- .../classes/java/io/DataInputStream.java | 33 +++++++++++-------- .../classes/java/io/ObjectInputStream.java | 13 ++++++-- .../classes/java/io/RandomAccessFile.java | 27 ++++++++------- 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/io/DataInput.java b/jdk/src/java.base/share/classes/java/io/DataInput.java index dca9187d4a7..60e03c2173c 100644 --- a/jdk/src/java.base/share/classes/java/io/DataInput.java +++ b/jdk/src/java.base/share/classes/java/io/DataInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * 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,10 +182,11 @@ interface DataInput { * not all bytes of {@code b} have been * updated with data from the input stream. * - * @param b the buffer into which the data is read. - * @exception EOFException if this stream reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. + * @param b the buffer into which the data is read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws EOFException if this stream reaches the end before reading + * all the bytes. + * @throws IOException if an I/O error occurs. */ void readFully(byte b[]) throws IOException; @@ -226,12 +227,16 @@ interface DataInput { * and so on. The number of bytes read is, * at most, equal to {@code len}. * - * @param b the buffer into which the data is read. - * @param off an int specifying the offset into the data. - * @param len an int specifying the number of bytes to read. - * @exception EOFException if this stream reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. + * @param b the buffer into which the data is read. + * @param off an int specifying the offset in the data array {@code b}. + * @param len an int specifying the number of bytes to read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws IndexOutOfBoundsException if {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code b.length - off}. + * @throws EOFException if this stream reaches the end before reading + * all the bytes. + * @throws IOException if an I/O error occurs. */ void readFully(byte b[], int off, int len) throws IOException; diff --git a/jdk/src/java.base/share/classes/java/io/DataInputStream.java b/jdk/src/java.base/share/classes/java/io/DataInputStream.java index 6ce6b233ee6..f92c4f91b0c 100644 --- a/jdk/src/java.base/share/classes/java/io/DataInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/DataInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -150,38 +150,43 @@ class DataInputStream extends FilterInputStream implements DataInput { } /** - * See the general contract of the readFully - * method of DataInput. + * See the general contract of the {@code readFully} + * method of {@code DataInput}. *

    * Bytes * for this operation are read from the contained * input stream. * - * @param b the buffer into which the data is read. - * @exception EOFException if this input stream reaches the end before - * reading all the bytes. - * @exception IOException the stream has been closed and the contained - * input stream does not support reading after close, or - * another I/O error occurs. - * @see java.io.FilterInputStream#in + * @param b the buffer into which the data is read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws EOFException if this input stream reaches the end before + * reading all the bytes. + * @throws IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in */ public final void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } /** - * See the general contract of the readFully - * method of DataInput. + * See the general contract of the {@code readFully} + * method of {@code DataInput}. *

    * Bytes * for this operation are read from the contained * input stream. * * @param b the buffer into which the data is read. - * @param off the start offset of the data. + * @param off the start offset in the data array {@code b}. * @param len the number of bytes to read. + * @exception NullPointerException if {@code b} is {@code null}. + * @exception IndexOutOfBoundsException if {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code b.length - off}. * @exception EOFException if this input stream reaches the end before - * reading all the bytes. + * reading all the bytes. * @exception IOException the stream has been closed and the contained * input stream does not support reading after close, or * another I/O error occurs. diff --git a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java index cd040d3d7e5..a591136419d 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -856,10 +856,14 @@ public class ObjectInputStream * exactly 'length' bytes. * * @param buf the buffer into which the data is read - * @param off the start offset of the data + * @param off the start offset in the destination array {@code buf} * @param len the maximum number of bytes read * @return the actual number of bytes read, -1 is returned when the end of * the stream is reached. + * @throws NullPointerException if {@code buf} is {@code null}. + * @throws IndexOutOfBoundsException if {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code buf.length - off}. * @throws IOException If an I/O error has occurred. * @see java.io.DataInputStream#readFully(byte[],int,int) */ @@ -1017,6 +1021,7 @@ public class ObjectInputStream * Reads bytes, blocking until all bytes are read. * * @param buf the buffer into which the data is read + * @throws NullPointerException If {@code buf} is {@code null}. * @throws EOFException If end of file is reached. * @throws IOException If other I/O error has occurred. */ @@ -1028,8 +1033,12 @@ public class ObjectInputStream * Reads bytes, blocking until all bytes are read. * * @param buf the buffer into which the data is read - * @param off the start offset of the data + * @param off the start offset into the data array {@code buf} * @param len the maximum number of bytes to read + * @throws NullPointerException If {@code buf} is {@code null}. + * @throws IndexOutOfBoundsException If {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code buf.length - off}. * @throws EOFException If end of file is reached. * @throws IOException If other I/O error has occurred. */ diff --git a/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java b/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java index db6ae71f89f..1a8344df88b 100644 --- a/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java +++ b/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -418,10 +418,11 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { * read. This method blocks until the requested number of bytes are * read, the end of the stream is detected, or an exception is thrown. * - * @param b the buffer into which the data is read. - * @exception EOFException if this file reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. + * @param b the buffer into which the data is read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws EOFException if this file reaches the end before reading + * all the bytes. + * @throws IOException if an I/O error occurs. */ public final void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); @@ -434,12 +435,16 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { * read. This method blocks until the requested number of bytes are * read, the end of the stream is detected, or an exception is thrown. * - * @param b the buffer into which the data is read. - * @param off the start offset of the data. - * @param len the number of bytes to read. - * @exception EOFException if this file reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. + * @param b the buffer into which the data is read. + * @param off the start offset into the data array {@code b}. + * @param len the number of bytes to read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws IndexOutOfBoundsException if {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code b.length - off}. + * @throws EOFException if this file reaches the end before reading + * all the bytes. + * @throws IOException if an I/O error occurs. */ public final void readFully(byte b[], int off, int len) throws IOException { int n = 0; From b909478b3d0e4d165ce32d49e43dc22f494974eb Mon Sep 17 00:00:00 2001 From: Amy Lu Date: Thu, 21 Apr 2016 14:56:40 +0800 Subject: [PATCH 119/222] 8152936: java/lang/Class/GetPackageTest.java needs update to work with newer testng Reviewed-by: alanb --- jdk/test/java/lang/Class/GetPackageTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/test/java/lang/Class/GetPackageTest.java b/jdk/test/java/lang/Class/GetPackageTest.java index d1ffea75ecb..f9cb5fb31ff 100644 --- a/jdk/test/java/lang/Class/GetPackageTest.java +++ b/jdk/test/java/lang/Class/GetPackageTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ public class GetPackageTest { assertEquals(fooClass.getClassLoader(), loader); } - @DataProvider(name = "testclasses") + @DataProvider(name = "testClasses") public Object[][] testClasses() { return new Object[][] { // primitive type, void, array types From 2b5207e74decb484e85ef01e4dd6d30f2d5e1d4c Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 21 Apr 2016 13:39:53 +0200 Subject: [PATCH 120/222] 8154231: Simplify access to System properties from JDK code Reviewed-by: rriggs, chegar, weijun --- .../sun/nio/fs/LinuxFileSystemProvider.java | 4 +- .../sun/nio/ch/KQueueArrayWrapper.java | 8 +-- .../sun/nio/fs/MacOSXFileSystemProvider.java | 5 +- .../java.base/share/classes/java/io/File.java | 5 +- .../classes/java/lang/ProcessBuilder.java | 13 ++-- .../classes/java/lang/StackStreamFactory.java | 12 +--- .../invoke/InnerClassLambdaMetafactory.java | 3 +- .../java/lang/invoke/MethodHandleStatics.java | 51 +++++++--------- .../java/lang/invoke/StringConcatFactory.java | 18 +++--- .../java/lang/module/ModuleFinder.java | 3 +- .../classes/java/lang/reflect/Proxy.java | 7 +-- .../net/AbstractPlainDatagramSocketImpl.java | 5 +- .../share/classes/java/net/InetAddress.java | 7 +-- .../classes/java/net/SocksSocketImpl.java | 7 +-- .../java.base/share/classes/java/net/URL.java | 9 +-- .../share/classes/java/net/URLConnection.java | 5 +- .../share/classes/java/net/URLEncoder.java | 11 +--- .../classes/java/nio/charset/Charset.java | 7 +-- .../classes/java/nio/file/TempFileHelper.java | 3 +- .../share/classes/java/util/Locale.java | 34 +++++------ .../java/util/PropertyResourceBundle.java | 5 +- .../share/classes/java/util/TimeZone.java | 6 +- .../share/classes/java/util/jar/JarFile.java | 9 ++- .../share/classes/java/util/jar/Pack200.java | 4 +- .../util/regex/PatternSyntaxException.java | 3 +- .../java/util/zip/ZipOutputStream.java | 5 +- .../javax/net/ssl/SSLSocketFactory.java | 6 +- .../java.base/share/classes/jdk/Version.java | 10 +-- .../jdk/internal/loader/URLClassPath.java | 15 ++--- .../internal/logger/LoggerFinderLoader.java | 11 ++-- .../internal/logger/SimpleConsoleLogger.java | 10 +-- .../jdk/internal/reflect/Reflection.java | 16 ++--- .../internal/reflect/ReflectionFactory.java | 61 +++++++++---------- .../classes/sun/net/ResourceManager.java | 5 +- .../share/classes/sun/net/sdp/SdpSupport.java | 4 +- .../classes/sun/net/smtp/SmtpClient.java | 8 +-- .../classes/sun/net/www/MimeLauncher.java | 4 +- .../classes/sun/net/www/http/HttpClient.java | 14 ++--- .../www/protocol/ftp/FtpURLConnection.java | 10 +-- .../protocol/http/AuthenticationHeader.java | 6 +- .../www/protocol/http/HttpURLConnection.java | 46 ++++++-------- .../net/www/protocol/https/HttpsClient.java | 12 ++-- .../jrt/JavaRuntimeURLConnection.java | 10 +-- .../sun/net/www/protocol/netdoc/Handler.java | 9 ++- .../classes/sun/nio/ch/FileChannelImpl.java | 5 +- .../share/classes/sun/nio/ch/Net.java | 21 ++----- .../share/classes/sun/nio/ch/Util.java | 11 +--- .../sun/nio/cs/StandardCharsets.java.template | 13 +--- .../share/classes/sun/nio/fs/Util.java | 5 +- .../sun/security/action/GetIntegerAction.java | 39 +++++++++++- .../security/action/GetPropertyAction.java | 60 +++++++++++++++++- .../sun/security/provider/DSAKeyFactory.java | 3 +- .../sun/security/rsa/RSAKeyFactory.java | 5 +- .../ssl/ClientKeyExchangeService.java | 5 +- .../share/classes/sun/security/ssl/Debug.java | 7 +-- .../sun/security/ssl/SSLContextImpl.java | 3 +- .../sun/security/ssl/ServerHandshaker.java | 4 +- .../security/ssl/StatusResponseManager.java | 4 +- .../classes/sun/security/util/Debug.java | 10 ++- .../util/calendar/LocalGregorianCalendar.java | 5 +- .../sun/util/calendar/ZoneInfoFile.java | 11 ++-- .../provider/LocaleProviderAdapter.java | 5 +- .../classes/sun/nio/fs/SolarisFileSystem.java | 4 +- .../sun/nio/fs/SolarisFileSystemProvider.java | 5 +- .../unix/classes/java/io/UnixFileSystem.java | 12 ++-- .../unix/classes/java/lang/ProcessImpl.java | 14 ++--- .../net/DefaultDatagramSocketImplFactory.java | 5 +- .../unix/classes/sun/net/sdp/SdpProvider.java | 7 +-- .../http/ntlm/NTLMAuthentication.java | 13 ++-- .../DefaultAsynchronousChannelProvider.java | 4 +- .../ch/UnixAsynchronousSocketChannelImpl.java | 5 +- .../sun/nio/fs/DefaultFileSystemProvider.java | 4 +- .../classes/sun/nio/fs/UnixFileSystem.java | 5 +- .../classes/java/io/WinNTFileSystem.java | 9 ++- .../net/DefaultDatagramSocketImplFactory.java | 13 ++-- .../http/ntlm/NTLMAuthentication.java | 6 +- .../sun/nio/ch/FileDispatcherImpl.java | 11 +--- .../sun/nio/fs/WindowsFileAttributes.java | 5 +- 78 files changed, 391 insertions(+), 453 deletions(-) diff --git a/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java b/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java index f6abaf69d7e..8a2307d2ff6 100644 --- a/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java +++ b/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java @@ -102,8 +102,8 @@ public class LinuxFileSystemProvider extends UnixFileSystemProvider { @Override FileTypeDetector getFileTypeDetector() { - Path userMimeTypes = Paths.get(AccessController.doPrivileged( - new GetPropertyAction("user.home")), ".mime.types"); + String userHome = GetPropertyAction.getProperty("user.home"); + Path userMimeTypes = Paths.get(userHome, ".mime.types"); Path etcMimeTypes = Paths.get("/etc/mime.types"); return chain(new GioFileTypeDetector(), diff --git a/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java b/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java index 2aa3fbcbaa2..7598cf9e37f 100644 --- a/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java +++ b/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java @@ -32,9 +32,9 @@ package sun.nio.ch; import java.io.IOException; -import java.io.FileDescriptor; import java.util.Iterator; import java.util.LinkedList; +import sun.security.action.GetPropertyAction; /* * struct kevent { // 32-bit 64-bit @@ -84,10 +84,8 @@ class KQueueArrayWrapper { static { IOUtil.load(); initStructSizes(); - String datamodel = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("sun.arch.data.model") - ); - is64bit = datamodel.equals("64"); + String datamodel = GetPropertyAction.getProperty("sun.arch.data.model"); + is64bit = "64".equals(datamodel); } KQueueArrayWrapper() { diff --git a/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java b/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java index 0dcee95bfc3..6b9a56a9fa7 100644 --- a/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java +++ b/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java @@ -28,7 +28,6 @@ package sun.nio.fs; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.spi.FileTypeDetector; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -47,8 +46,8 @@ public class MacOSXFileSystemProvider extends BsdFileSystemProvider { @Override FileTypeDetector getFileTypeDetector() { - Path userMimeTypes = Paths.get(AccessController.doPrivileged( - new GetPropertyAction("user.home")), ".mime.types"); + Path userMimeTypes = Paths.get( + GetPropertyAction.getProperty("user.home"), ".mime.types"); return chain(new MimeTypesFileTypeDetector(userMimeTypes), new UTIFileTypeDetector()); diff --git a/jdk/src/java.base/share/classes/java/io/File.java b/jdk/src/java.base/share/classes/java/io/File.java index 089171bab9e..7f23340920b 100644 --- a/jdk/src/java.base/share/classes/java/io/File.java +++ b/jdk/src/java.base/share/classes/java/io/File.java @@ -31,7 +31,6 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.util.List; import java.util.ArrayList; -import java.security.AccessController; import java.security.SecureRandom; import java.nio.file.Path; import java.nio.file.FileSystems; @@ -1896,8 +1895,8 @@ public class File private TempDirectory() { } // temporary directory location - private static final File tmpdir = new File(AccessController - .doPrivileged(new GetPropertyAction("java.io.tmpdir"))); + private static final File tmpdir = new File( + GetPropertyAction.getProperty("java.io.tmpdir")); static File location() { return tmpdir; } diff --git a/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java b/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java index ebd47fcfe87..638be0e9f72 100644 --- a/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java +++ b/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java @@ -30,13 +30,12 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.nio.channels.Pipe; import java.util.Arrays; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.security.AccessController; -import java.security.PrivilegedAction; +import sun.security.action.GetPropertyAction; + /** * This class is used to create operating system processes. * @@ -468,11 +467,9 @@ public final class ProcessBuilder * @since 1.7 */ public abstract static class Redirect { - private static final File NULL_FILE = AccessController.doPrivileged( - (PrivilegedAction) () -> { - return new File((System.getProperty("os.name") - .startsWith("Windows") ? "NUL" : "/dev/null")); - } + private static final File NULL_FILE = new File( + (GetPropertyAction.getProperty("os.name") + .startsWith("Windows") ? "NUL" : "/dev/null") ); /** diff --git a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java index 8dccef351fe..73446062bea 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -30,8 +30,6 @@ import java.lang.StackWalker.StackFrame; import java.lang.annotation.Native; import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Objects; @@ -41,6 +39,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import sun.security.action.GetPropertyAction; import static java.lang.StackStreamFactory.WalkerState.*; @@ -990,14 +989,9 @@ final class StackStreamFactory { } private static boolean getProperty(String key, boolean value) { - String s = AccessController.doPrivileged(new PrivilegedAction<>() { - @Override - public String run() { - return System.getProperty(key); - } - }); + String s = GetPropertyAction.getProperty(key); if (s != null) { - return Boolean.valueOf(s); + return Boolean.parseBoolean(s); } return value; } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 739573507ab..a0df622f501 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -88,8 +88,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; static { final String key = "jdk.internal.lambda.dumpProxyClasses"; - String path = AccessController.doPrivileged( - new GetPropertyAction(key)); + String path = GetPropertyAction.getProperty(key); dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path); } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java index df1cba46fa8..4fbc1d84671 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java @@ -25,9 +25,9 @@ package java.lang.invoke; -import java.security.AccessController; -import java.security.PrivilegedAction; +import java.util.Properties; import jdk.internal.misc.Unsafe; +import sun.security.action.GetPropertyAction; /** * This class consists exclusively of static names internal to the @@ -53,32 +53,27 @@ import jdk.internal.misc.Unsafe; static final boolean VAR_HANDLE_GUARDS; static { - final Object[] values = new Object[10]; - AccessController.doPrivileged(new PrivilegedAction<>() { - public Void run() { - values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); - values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES"); - values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER"); - values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE"); - values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 0); - values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30); - values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0); - values[7] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true")); - values[8] = Integer.getInteger("java.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD", 127); - values[9] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.VarHandle.VAR_HANDLE_GUARDS", "true")); - return null; - } - }); - DEBUG_METHOD_HANDLE_NAMES = (Boolean) values[0]; - DUMP_CLASS_FILES = (Boolean) values[1]; - TRACE_INTERPRETER = (Boolean) values[2]; - TRACE_METHOD_LINKAGE = (Boolean) values[3]; - COMPILE_THRESHOLD = (Integer) values[4]; - DONT_INLINE_THRESHOLD = (Integer) values[5]; - PROFILE_LEVEL = (Integer) values[6]; - PROFILE_GWT = (Boolean) values[7]; - CUSTOMIZE_THRESHOLD = (Integer) values[8]; - VAR_HANDLE_GUARDS = (Boolean) values[9]; + Properties props = GetPropertyAction.getProperties(); + DEBUG_METHOD_HANDLE_NAMES = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.DEBUG_NAMES")); + DUMP_CLASS_FILES = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES")); + TRACE_INTERPRETER = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.TRACE_INTERPRETER")); + TRACE_METHOD_LINKAGE = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE")); + COMPILE_THRESHOLD = Integer.parseInt( + props.getProperty("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", "0")); + DONT_INLINE_THRESHOLD = Integer.parseInt( + props.getProperty("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", "30")); + PROFILE_LEVEL = Integer.parseInt( + props.getProperty("java.lang.invoke.MethodHandle.PROFILE_LEVEL", "0")); + PROFILE_GWT = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true")); + CUSTOMIZE_THRESHOLD = Integer.parseInt( + props.getProperty("java.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD", "127")); + VAR_HANDLE_GUARDS = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.VarHandle.VAR_HANDLE_GUARDS", "true")); if (CUSTOMIZE_THRESHOLD < -1 || CUSTOMIZE_THRESHOLD > 127) { throw newInternalError("CUSTOMIZE_THRESHOLD should be in [-1...127] range"); diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 6469a4b8a6d..44f29a4a136 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -33,7 +33,6 @@ import jdk.internal.vm.annotation.ForceInline; import jdk.internal.misc.Unsafe; import java.lang.invoke.MethodHandles.Lookup; -import java.security.AccessController; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -188,14 +187,15 @@ public final class StringConcatFactory { private static final ProxyClassesDumper DUMPER; static { - final String strategy = AccessController.doPrivileged( - new GetPropertyAction("java.lang.invoke.stringConcat")); - CACHE_ENABLE = Boolean.parseBoolean(AccessController.doPrivileged( - new GetPropertyAction("java.lang.invoke.stringConcat.cache"))); - DEBUG = Boolean.parseBoolean(AccessController.doPrivileged( - new GetPropertyAction("java.lang.invoke.stringConcat.debug"))); - final String dumpPath = AccessController.doPrivileged( - new GetPropertyAction("java.lang.invoke.stringConcat.dumpClasses")); + Properties props = GetPropertyAction.getProperties(); + final String strategy = + props.getProperty("java.lang.invoke.stringConcat"); + CACHE_ENABLE = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.stringConcat.cache")); + DEBUG = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.stringConcat.debug")); + final String dumpPath = + props.getProperty("java.lang.invoke.stringConcat.dumpClasses"); STRATEGY = (strategy == null) ? DEFAULT_STRATEGY : Strategy.valueOf(strategy); CACHE = CACHE_ENABLE ? new ConcurrentHashMap<>() : null; diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java index 83d8fc59aaf..1cdd12838b1 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java @@ -39,6 +39,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import sun.security.action.GetPropertyAction; /** * A finder of modules. A {@code ModuleFinder} is used to find modules during @@ -152,7 +153,7 @@ public interface ModuleFinder { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - PrivilegedAction pa = () -> System.getProperty("java.home"); + PrivilegedAction pa = new GetPropertyAction("java.home"); home = AccessController.doPrivileged(pa); Permission p = new FilePermission(home + File.separator + "-", "read"); sm.checkPermission(p); diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java index 12abe79d4ea..8802abeda76 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java @@ -50,6 +50,7 @@ import jdk.internal.misc.VM; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; +import sun.security.action.GetPropertyAction; import sun.security.util.SecurityConstants; /** @@ -581,11 +582,7 @@ public class Proxy implements java.io.Serializable { } private static final String DEBUG = - AccessController.doPrivileged(new PrivilegedAction<>() { - public String run() { - return System.getProperty("jdk.proxy.debug", ""); - } - }); + GetPropertyAction.getProperty("jdk.proxy.debug", ""); private static boolean isDebug() { return !DEBUG.isEmpty(); diff --git a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java index 7a9b7fc17ed..debc60f74b9 100644 --- a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java +++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java @@ -31,6 +31,7 @@ import sun.net.ResourceManager; import java.util.Set; import java.util.HashSet; import java.util.Collections; +import sun.security.action.GetPropertyAction; /** * Abstract datagram and multicast socket implementation base class. @@ -51,9 +52,7 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl protected InetAddress connectedAddress = null; private int connectedPort = -1; - private static final String os = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("os.name") - ); + private static final String os = GetPropertyAction.getProperty("os.name"); /** * flag set if the native connect() call not to be used diff --git a/jdk/src/java.base/share/classes/java/net/InetAddress.java b/jdk/src/java.base/share/classes/java/net/InetAddress.java index 8e0d46152ff..e79c5115413 100644 --- a/jdk/src/java.base/share/classes/java/net/InetAddress.java +++ b/jdk/src/java.base/share/classes/java/net/InetAddress.java @@ -1123,8 +1123,8 @@ class InetAddress implements java.io.Serializable { */ private static NameService createNameService() { - String hostsFileName = AccessController - .doPrivileged(new GetPropertyAction("jdk.net.hosts.file")); + String hostsFileName = + GetPropertyAction.getProperty("jdk.net.hosts.file"); NameService theNameService; if (hostsFileName != null) { theNameService = new HostsFileNameService(hostsFileName); @@ -1643,8 +1643,7 @@ class InetAddress implements java.io.Serializable { * property can vary across implementations of the java. * classes. The default is an empty String "". */ - String prefix = AccessController.doPrivileged( - new GetPropertyAction("impl.prefix", "")); + String prefix = GetPropertyAction.getProperty("impl.prefix", ""); try { impl = Class.forName("java.net." + prefix + implName).newInstance(); } catch (ClassNotFoundException e) { diff --git a/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java b/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java index f7974d0d705..c3a0d1c675a 100644 --- a/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java +++ b/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java @@ -33,6 +33,7 @@ import java.security.PrivilegedExceptionAction; import sun.net.SocksProxy; import sun.net.spi.DefaultProxySelector; import sun.net.www.ParseUtil; +import sun.security.action.GetPropertyAction; /* import org.ietf.jgss.*; */ /** @@ -177,8 +178,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts { userName = pw.getUserName(); password = new String(pw.getPassword()); } else { - userName = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("user.name")); + userName = GetPropertyAction.getProperty("user.name"); } if (userName == null) return false; @@ -1088,8 +1088,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts { userName = System.getProperty("user.name"); } catch (SecurityException se) { /* swallow Exception */ } } else { - userName = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("user.name")); + userName = GetPropertyAction.getProperty("user.name"); } return userName; } diff --git a/jdk/src/java.base/share/classes/java/net/URL.java b/jdk/src/java.base/share/classes/java/net/URL.java index cce9cf9425a..099e8b9e0c8 100644 --- a/jdk/src/java.base/share/classes/java/net/URL.java +++ b/jdk/src/java.base/share/classes/java/net/URL.java @@ -42,6 +42,7 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import sun.security.util.SecurityConstants; +import sun.security.action.GetPropertyAction; /** * Class {@code URL} represents a Uniform Resource @@ -1210,12 +1211,8 @@ public final class URL implements java.io.Serializable { } private static URLStreamHandler lookupViaProperty(String protocol) { - String packagePrefixList = java.security.AccessController.doPrivileged( - new PrivilegedAction<>() { - public String run() { - return System.getProperty(protocolPathProp, null); - } - }); + String packagePrefixList = + GetPropertyAction.getProperty(protocolPathProp); if (packagePrefixList == null) { // not set return null; diff --git a/jdk/src/java.base/share/classes/java/net/URLConnection.java b/jdk/src/java.base/share/classes/java/net/URLConnection.java index 87f4378b2ad..459a820bcde 100644 --- a/jdk/src/java.base/share/classes/java/net/URLConnection.java +++ b/jdk/src/java.base/share/classes/java/net/URLConnection.java @@ -43,6 +43,7 @@ import java.security.Permission; import java.security.AccessController; import sun.security.util.SecurityConstants; import sun.net.www.MessageHeader; +import sun.security.action.GetPropertyAction; /** * The abstract class {@code URLConnection} is the superclass @@ -1395,8 +1396,8 @@ public abstract class URLConnection { * is always the last one on the returned package list. */ private String getContentHandlerPkgPrefixes() { - String packagePrefixList = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction(contentPathProp, "")); + String packagePrefixList = + GetPropertyAction.getProperty(contentPathProp, ""); if (packagePrefixList != "") { packagePrefixList += "|"; diff --git a/jdk/src/java.base/share/classes/java/net/URLEncoder.java b/jdk/src/java.base/share/classes/java/net/URLEncoder.java index 5ad817bc72c..2f2c3e6c9c4 100644 --- a/jdk/src/java.base/share/classes/java/net/URLEncoder.java +++ b/jdk/src/java.base/share/classes/java/net/URLEncoder.java @@ -25,19 +25,12 @@ package java.net; -import java.io.ByteArrayOutputStream; -import java.io.BufferedWriter; -import java.io.OutputStreamWriter; -import java.io.IOException; import java.io.UnsupportedEncodingException; import java.io.CharArrayWriter; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException ; import java.util.BitSet; -import java.security.AccessController; -import java.security.PrivilegedAction; -import sun.security.action.GetBooleanAction; import sun.security.action.GetPropertyAction; /** @@ -140,9 +133,7 @@ public class URLEncoder { dontNeedEncoding.set('.'); dontNeedEncoding.set('*'); - dfltEncName = AccessController.doPrivileged( - new GetPropertyAction("file.encoding") - ); + dfltEncName = GetPropertyAction.getProperty("file.encoding"); } /** diff --git a/jdk/src/java.base/share/classes/java/nio/charset/Charset.java b/jdk/src/java.base/share/classes/java/nio/charset/Charset.java index 78ee33e764a..de49a8c6271 100644 --- a/jdk/src/java.base/share/classes/java/nio/charset/Charset.java +++ b/jdk/src/java.base/share/classes/java/nio/charset/Charset.java @@ -283,8 +283,8 @@ public abstract class Charset if (level == null) { if (!VM.isBooted()) return false; - bugLevel = level = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.cs.bugLevel", "")); + bugLevel = level = + GetPropertyAction.getProperty("sun.nio.cs.bugLevel", ""); } return level.equals(bl); } @@ -609,8 +609,7 @@ public abstract class Charset public static Charset defaultCharset() { if (defaultCharset == null) { synchronized (Charset.class) { - String csn = AccessController.doPrivileged( - new GetPropertyAction("file.encoding")); + String csn = GetPropertyAction.getProperty("file.encoding"); Charset cs = lookup(csn); if (cs != null) defaultCharset = cs; diff --git a/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java b/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java index 2bc3d992c60..a6af1a15b1f 100644 --- a/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java +++ b/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java @@ -28,7 +28,6 @@ package java.nio.file; import java.util.Set; import java.util.EnumSet; import java.security.SecureRandom; -import static java.security.AccessController.*; import java.io.IOException; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.PosixFilePermission; @@ -47,7 +46,7 @@ class TempFileHelper { // temporary directory location private static final Path tmpdir = - Paths.get(doPrivileged(new GetPropertyAction("java.io.tmpdir"))); + Paths.get(GetPropertyAction.getProperty("java.io.tmpdir")); private static final boolean isPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); diff --git a/jdk/src/java.base/share/classes/java/util/Locale.java b/jdk/src/java.base/share/classes/java/util/Locale.java index 2d121e2e7ef..e05904f6f6b 100644 --- a/jdk/src/java.base/share/classes/java/util/Locale.java +++ b/jdk/src/java.base/share/classes/java/util/Locale.java @@ -45,7 +45,6 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.io.Serializable; -import java.security.AccessController; import java.text.MessageFormat; import java.util.spi.LocaleNameProvider; @@ -859,11 +858,10 @@ public final class Locale implements Cloneable, Serializable { private static Locale initDefault() { String language, region, script, country, variant; - language = AccessController.doPrivileged( - new GetPropertyAction("user.language", "en")); + Properties props = GetPropertyAction.getProperties(); + language = props.getProperty("user.language", "en"); // for compatibility, check for old user.region property - region = AccessController.doPrivileged( - new GetPropertyAction("user.region")); + region = props.getProperty("user.region"); if (region != null) { // region can be of form country, country_variant, or _variant int i = region.indexOf('_'); @@ -876,27 +874,25 @@ public final class Locale implements Cloneable, Serializable { } script = ""; } else { - script = AccessController.doPrivileged( - new GetPropertyAction("user.script", "")); - country = AccessController.doPrivileged( - new GetPropertyAction("user.country", "")); - variant = AccessController.doPrivileged( - new GetPropertyAction("user.variant", "")); + script = props.getProperty("user.script", ""); + country = props.getProperty("user.country", ""); + variant = props.getProperty("user.variant", ""); } return getInstance(language, script, country, variant, null); } private static Locale initDefault(Locale.Category category) { + Properties props = GetPropertyAction.getProperties(); return getInstance( - AccessController.doPrivileged( - new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())), - AccessController.doPrivileged( - new GetPropertyAction(category.scriptKey, defaultLocale.getScript())), - AccessController.doPrivileged( - new GetPropertyAction(category.countryKey, defaultLocale.getCountry())), - AccessController.doPrivileged( - new GetPropertyAction(category.variantKey, defaultLocale.getVariant())), + props.getProperty(category.languageKey, + defaultLocale.getLanguage()), + props.getProperty(category.scriptKey, + defaultLocale.getScript()), + props.getProperty(category.countryKey, + defaultLocale.getCountry()), + props.getProperty(category.variantKey, + defaultLocale.getVariant()), null); } diff --git a/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java b/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java index 58ff7570269..9c20a680733 100644 --- a/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java +++ b/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java @@ -43,7 +43,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.IOException; -import java.nio.charset.Charset; import java.nio.charset.MalformedInputException; import java.nio.charset.StandardCharsets; import java.nio.charset.UnmappableCharacterException; @@ -142,8 +141,8 @@ public class PropertyResourceBundle extends ResourceBundle { // Check whether the strict encoding is specified. // The possible encoding is either "ISO-8859-1" or "UTF-8". private static final String encoding = - AccessController.doPrivileged( - new GetPropertyAction("java.util.PropertyResourceBundle.encoding", "")) + GetPropertyAction + .getProperty("java.util.PropertyResourceBundle.encoding", "") .toUpperCase(Locale.ROOT); /** diff --git a/jdk/src/java.base/share/classes/java/util/TimeZone.java b/jdk/src/java.base/share/classes/java/util/TimeZone.java index 3bf886b2721..22c382cb0a2 100644 --- a/jdk/src/java.base/share/classes/java/util/TimeZone.java +++ b/jdk/src/java.base/share/classes/java/util/TimeZone.java @@ -660,14 +660,12 @@ public abstract class TimeZone implements Serializable, Cloneable { private static synchronized TimeZone setDefaultZone() { TimeZone tz; // get the time zone ID from the system properties - String zoneID = AccessController.doPrivileged( - new GetPropertyAction("user.timezone")); + String zoneID = GetPropertyAction.getProperty("user.timezone"); // if the time zone ID is not set (yet), perform the // platform to Java time zone ID mapping. if (zoneID == null || zoneID.isEmpty()) { - String javaHome = AccessController.doPrivileged( - new GetPropertyAction("java.home")); + String javaHome = GetPropertyAction.getProperty("java.home"); try { zoneID = getSystemTimeZoneID(javaHome); if (zoneID == null) { diff --git a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java index f28750c3a97..ff26faad4f4 100644 --- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java @@ -34,7 +34,6 @@ import java.util.stream.StreamSupport; import java.util.zip.*; import java.security.CodeSigner; import java.security.cert.Certificate; -import java.security.AccessController; import java.security.CodeSource; import jdk.internal.misc.SharedSecrets; import sun.security.action.GetPropertyAction; @@ -155,16 +154,16 @@ class JarFile extends ZipFile { BASE_VERSION = 8; // one less than lowest version for versioned entries int runtimeVersion = jdk.Version.current().major(); - String jarVersion = AccessController.doPrivileged( - new GetPropertyAction("jdk.util.jar.version")); + String jarVersion = + GetPropertyAction.getProperty("jdk.util.jar.version"); if (jarVersion != null) { int jarVer = Integer.parseInt(jarVersion); runtimeVersion = (jarVer > runtimeVersion) ? runtimeVersion : Math.max(jarVer, 0); } RUNTIME_VERSION = runtimeVersion; - String enableMultiRelease = AccessController.doPrivileged( - new GetPropertyAction("jdk.util.jar.enableMultiRelease", "true")); + String enableMultiRelease = GetPropertyAction + .getProperty("jdk.util.jar.enableMultiRelease", "true"); switch (enableMultiRelease) { case "true": default: diff --git a/jdk/src/java.base/share/classes/java/util/jar/Pack200.java b/jdk/src/java.base/share/classes/java/util/jar/Pack200.java index 44f1cccd080..ac47ad12032 100644 --- a/jdk/src/java.base/share/classes/java/util/jar/Pack200.java +++ b/jdk/src/java.base/share/classes/java/util/jar/Pack200.java @@ -29,6 +29,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.File; import java.io.IOException; +import sun.security.action.GetPropertyAction; /** @@ -694,8 +695,7 @@ public abstract class Pack200 { Class impl = (PACK_PROVIDER.equals(prop))? packerImpl: unpackerImpl; if (impl == null) { // The first time, we must decide which class to use. - implName = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction(prop,"")); + implName = GetPropertyAction.getProperty(prop,""); if (implName != null && !implName.equals("")) impl = Class.forName(implName); else if (PACK_PROVIDER.equals(prop)) diff --git a/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java b/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java index 94d7abc78a5..f7768da27da 100644 --- a/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java +++ b/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java @@ -94,8 +94,7 @@ public class PatternSyntaxException } private static final String nl = - java.security.AccessController - .doPrivileged(new GetPropertyAction("line.separator")); + GetPropertyAction.getProperty("line.separator"); /** * Returns a multi-line string containing the description of the syntax diff --git a/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java index 6b480aa1d5e..ff76017651b 100644 --- a/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java +++ b/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java @@ -33,6 +33,7 @@ import java.util.Vector; import java.util.HashSet; import static java.util.zip.ZipConstants64.*; import static java.util.zip.ZipUtils.*; +import sun.security.action.GetPropertyAction; /** * This class implements an output stream filter for writing files in the @@ -54,9 +55,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { */ private static final boolean inhibitZip64 = Boolean.parseBoolean( - java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction( - "jdk.util.zip.inhibitZip64", "false"))); + GetPropertyAction.getProperty("jdk.util.zip.inhibitZip64")); private static class XEntry { final ZipEntry entry; diff --git a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java index 316016aac35..b436414308f 100644 --- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java +++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java @@ -51,9 +51,9 @@ public abstract class SSLSocketFactory extends SocketFactory static final boolean DEBUG; static { - String s = java.security.AccessController.doPrivileged( - new GetPropertyAction("javax.net.debug", "")).toLowerCase( - Locale.ENGLISH); + String s = GetPropertyAction.getProperty("javax.net.debug", "") + .toLowerCase(Locale.ENGLISH); + DEBUG = s.contains("all") || s.contains("ssl"); } diff --git a/jdk/src/java.base/share/classes/jdk/Version.java b/jdk/src/java.base/share/classes/jdk/Version.java index 75c6b35c444..756af9ec051 100644 --- a/jdk/src/java.base/share/classes/jdk/Version.java +++ b/jdk/src/java.base/share/classes/jdk/Version.java @@ -26,8 +26,6 @@ package jdk; import java.math.BigInteger; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,6 +33,7 @@ import java.util.stream.Collectors; import java.util.Collections; import java.util.List; import java.util.Optional; +import sun.security.action.GetPropertyAction; /** * A representation of the JDK version-string which contains a version @@ -274,12 +273,7 @@ public final class Version */ public static Version current() { if (current == null) { - current = parse(AccessController.doPrivileged( - new PrivilegedAction<>() { - public String run() { - return System.getProperty("java.version"); - } - })); + current = parse(GetPropertyAction.getProperty("java.version")); } return current; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java index 15688e1a573..234a86a9271 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -52,6 +52,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; +import java.util.Properties; import java.util.Set; import java.util.Stack; import java.util.StringTokenizer; @@ -69,6 +70,7 @@ import jdk.internal.util.jar.InvalidJarIndexError; import jdk.internal.util.jar.JarIndex; import sun.net.util.URLUtil; import sun.net.www.ParseUtil; +import sun.security.action.GetPropertyAction; /** * This class is used to maintain a search path of URLs for loading classes @@ -78,20 +80,15 @@ import sun.net.www.ParseUtil; */ public class URLClassPath { private static final String USER_AGENT_JAVA_VERSION = "UA-Java-Version"; - private static final String JAVA_HOME; private static final String JAVA_VERSION; private static final boolean DEBUG; private static final boolean DISABLE_JAR_CHECKING; static { - JAVA_HOME = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("java.home")); - JAVA_VERSION = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("java.version")); - DEBUG = (java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.debug")) != null); - String p = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.disableJarChecking")); + Properties props = GetPropertyAction.getProperties(); + JAVA_VERSION = props.getProperty("java.version"); + DEBUG = (props.getProperty("sun.misc.URLClassPath.debug") != null); + String p = props.getProperty("sun.misc.URLClassPath.disableJarChecking"); DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java b/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java index 7d315ba7057..58f235d6ccd 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java @@ -33,6 +33,7 @@ import java.util.Locale; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import sun.security.util.SecurityConstants; +import sun.security.action.GetPropertyAction; /** * Helper class used to load the {@link java.lang.System.LoggerFinder}. @@ -79,9 +80,8 @@ public final class LoggerFinderLoader { // Get configuration error policy private static ErrorPolicy configurationErrorPolicy() { - final PrivilegedAction getConfigurationErrorPolicy = - () -> System.getProperty("jdk.logger.finder.error"); - String errorPolicy = AccessController.doPrivileged(getConfigurationErrorPolicy); + String errorPolicy = + GetPropertyAction.getProperty("jdk.logger.finder.error"); if (errorPolicy == null || errorPolicy.isEmpty()) { return ErrorPolicy.WARNING; } @@ -95,9 +95,8 @@ public final class LoggerFinderLoader { // Whether multiple provider should be considered as an error. // This is further submitted to the configuration error policy. private static boolean ensureSingletonProvider() { - final PrivilegedAction ensureSingletonProvider = - () -> Boolean.getBoolean("jdk.logger.finder.singleton"); - return AccessController.doPrivileged(ensureSingletonProvider); + return Boolean.parseBoolean( + GetPropertyAction.getProperty("jdk.logger.finder.singleton")); } private static Iterator findLoggerFinderProviders() { diff --git a/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java b/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java index de4451fd35c..c90a7b24e38 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java +++ b/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java @@ -55,8 +55,8 @@ public class SimpleConsoleLogger extends LoggerConfiguration PlatformLogger.toPlatformLevel(DEFAULT_LEVEL); static Level getDefaultLevel() { - String levelName = AccessController.doPrivileged( - new GetPropertyAction("jdk.system.logger.level", "INFO")); + String levelName = GetPropertyAction + .getProperty("jdk.system.logger.level", "INFO"); try { return Level.valueOf(levelName); } catch (IllegalArgumentException iae) { @@ -425,8 +425,8 @@ public class SimpleConsoleLogger extends LoggerConfiguration // Make it easier to wrap Logger... static private final String[] skips; static { - String additionalPkgs = AccessController.doPrivileged( - new GetPropertyAction("jdk.logger.packages")); + String additionalPkgs = + GetPropertyAction.getProperty("jdk.logger.packages"); skips = additionalPkgs == null ? new String[0] : additionalPkgs.split(","); } @@ -485,7 +485,7 @@ public class SimpleConsoleLogger extends LoggerConfiguration // jdk/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java // to fail - because that test has a testcase which somehow references // PlatformLogger and counts the number of generated lambda classes. - String format = AccessController.doPrivileged(new GetPropertyAction(key)); + String format = GetPropertyAction.getProperty(key); if (format == null && defaultPropertyGetter != null) { format = defaultPropertyGetter.apply(key); diff --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index 88e6a8349ca..636b0940345 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -27,13 +27,12 @@ package jdk.internal.reflect; import java.lang.reflect.*; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; import java.util.Objects; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.misc.VM; +import sun.security.action.GetPropertyAction; /** Common utility routines used by both java.lang and java.lang.reflect */ @@ -344,15 +343,10 @@ public class Reflection { private static void printStackTraceIfNeeded(Throwable e) { if (!printStackWhenAccessFailsSet && VM.initLevel() >= 1) { - // can't use method reference here, might be too early in startup - PrivilegedAction pa = new PrivilegedAction() { - public Boolean run() { - String s; - s = System.getProperty("sun.reflect.debugModuleAccessChecks"); - return (s != null && !s.equalsIgnoreCase("false")); - } - }; - printStackWhenAccessFails = AccessController.doPrivileged(pa); + String s = GetPropertyAction + .getProperty("sun.reflect.debugModuleAccessChecks"); + printStackWhenAccessFails = + (s != null && !s.equalsIgnoreCase("false")); printStackWhenAccessFailsSet = true; } if (printStackWhenAccessFails) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java index 898f56c214f..b40c584efcd 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -30,10 +30,11 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; -import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedAction; +import java.util.Properties; import sun.reflect.misc.ReflectUtil; +import sun.security.action.GetPropertyAction; /**

    The master factory for all reflective objects, both those in java.lang.reflect (Fields, Methods, Constructors) as well as their @@ -382,41 +383,37 @@ public class ReflectionFactory { run, before the system properties are set up. */ private static void checkInitted() { if (initted) return; - AccessController.doPrivileged( - new PrivilegedAction<>() { - public Void run() { - // Tests to ensure the system properties table is fully - // initialized. This is needed because reflection code is - // called very early in the initialization process (before - // command-line arguments have been parsed and therefore - // these user-settable properties installed.) We assume that - // if System.out is non-null then the System class has been - // fully initialized and that the bulk of the startup code - // has been run. - if (System.out == null) { - // java.lang.System not yet fully initialized - return null; - } + // Tests to ensure the system properties table is fully + // initialized. This is needed because reflection code is + // called very early in the initialization process (before + // command-line arguments have been parsed and therefore + // these user-settable properties installed.) We assume that + // if System.out is non-null then the System class has been + // fully initialized and that the bulk of the startup code + // has been run. - String val = System.getProperty("sun.reflect.noInflation"); - if (val != null && val.equals("true")) { - noInflation = true; - } + if (System.out == null) { + // java.lang.System not yet fully initialized + return; + } - val = System.getProperty("sun.reflect.inflationThreshold"); - if (val != null) { - try { - inflationThreshold = Integer.parseInt(val); - } catch (NumberFormatException e) { - throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e); - } - } + Properties props = GetPropertyAction.getProperties(); + String val = props.getProperty("sun.reflect.noInflation"); + if (val != null && val.equals("true")) { + noInflation = true; + } - initted = true; - return null; - } - }); + val = props.getProperty("sun.reflect.inflationThreshold"); + if (val != null) { + try { + inflationThreshold = Integer.parseInt(val); + } catch (NumberFormatException e) { + throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e); + } + } + + initted = true; } private static LangReflectAccess langReflectAccess() { diff --git a/jdk/src/java.base/share/classes/sun/net/ResourceManager.java b/jdk/src/java.base/share/classes/sun/net/ResourceManager.java index 068b8484728..9c68d7c6bed 100644 --- a/jdk/src/java.base/share/classes/sun/net/ResourceManager.java +++ b/jdk/src/java.base/share/classes/sun/net/ResourceManager.java @@ -53,9 +53,8 @@ public class ResourceManager { private static final AtomicInteger numSockets; static { - String prop = java.security.AccessController.doPrivileged( - new GetPropertyAction("sun.net.maxDatagramSockets") - ); + String prop = + GetPropertyAction.getProperty("sun.net.maxDatagramSockets"); int defmax = DEFAULT_MAX_SOCKETS; try { if (prop != null) { diff --git a/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java b/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java index d24a7fed491..797bc7fed50 100644 --- a/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java +++ b/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java @@ -31,6 +31,7 @@ import java.security.AccessController; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.JavaIOFileDescriptorAccess; +import sun.security.action.GetPropertyAction; /** @@ -39,8 +40,7 @@ import jdk.internal.misc.JavaIOFileDescriptorAccess; */ public final class SdpSupport { - private static final String os = AccessController - .doPrivileged(new sun.security.action.GetPropertyAction("os.name")); + private static final String os = GetPropertyAction.getProperty("os.name"); private static final boolean isSupported = (os.equals("SunOS") || (os.equals("Linux"))); private static final JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess(); diff --git a/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java b/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java index fda15ea9234..ac3f7b8a43f 100644 --- a/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java +++ b/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java @@ -25,10 +25,10 @@ package sun.net.smtp; -import java.util.StringTokenizer; import java.io.*; import java.net.*; import sun.net.TransferProtocolClient; +import sun.security.action.GetPropertyAction; /** * This class implements the SMTP client. @@ -157,8 +157,7 @@ public class SmtpClient extends TransferProtocolClient { } try { String s; - mailhost = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("mail.host")); + mailhost = GetPropertyAction.getProperty("mail.host"); if (mailhost != null) { openServer(mailhost); return; @@ -184,8 +183,7 @@ public class SmtpClient extends TransferProtocolClient { setConnectTimeout(to); try { String s; - mailhost = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("mail.host")); + mailhost = GetPropertyAction.getProperty("mail.host"); if (mailhost != null) { openServer(mailhost); return; diff --git a/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java b/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java index d95ca3774ba..ba26f96e52e 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java +++ b/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java @@ -27,6 +27,7 @@ package sun.net.www; import java.net.URL; import java.io.*; import java.util.StringTokenizer; +import sun.security.action.GetPropertyAction; class MimeLauncher extends Thread { java.net.URLConnection uc; @@ -182,8 +183,7 @@ class MimeLauncher extends Thread { } String execPathList; - execPathList = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("exec.path")); + execPathList = GetPropertyAction.getProperty("exec.path"); if (execPathList == null) { // exec.path property not set return false; diff --git a/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java b/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java index 02c9f98b7a6..392d9ea52dc 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java +++ b/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java @@ -28,6 +28,7 @@ package sun.net.www.http; import java.io.*; import java.net.*; import java.util.Locale; +import java.util.Properties; import sun.net.NetworkClient; import sun.net.ProgressSource; import sun.net.www.MessageHeader; @@ -37,6 +38,7 @@ import sun.net.www.ParseUtil; import sun.net.www.protocol.http.HttpURLConnection; import sun.util.logging.PlatformLogger; import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*; +import sun.security.action.GetPropertyAction; /** * @author Herb Jellinek @@ -143,20 +145,18 @@ public class HttpClient extends NetworkClient { } static { - String keepAlive = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.keepAlive")); - - String retryPost = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("sun.net.http.retryPost")); + Properties props = GetPropertyAction.getProperties(); + String keepAlive = props.getProperty("http.keepAlive"); + String retryPost = props.getProperty("sun.net.http.retryPost"); if (keepAlive != null) { - keepAliveProp = Boolean.valueOf(keepAlive).booleanValue(); + keepAliveProp = Boolean.parseBoolean(keepAlive); } else { keepAliveProp = true; } if (retryPost != null) { - retryPostProp = Boolean.valueOf(retryPost).booleanValue(); + retryPostProp = Boolean.parseBoolean(retryPost); } else retryPostProp = true; diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java index 38d64d23009..b397ba1243f 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java @@ -46,6 +46,7 @@ import java.net.ProxySelector; import java.util.StringTokenizer; import java.util.Iterator; import java.security.Permission; +import java.util.Properties; import sun.net.NetworkClient; import sun.net.www.MessageHeader; import sun.net.www.MeteredStream; @@ -277,11 +278,10 @@ public class FtpURLConnection extends URLConnection { if (user == null) { user = "anonymous"; - String vers = java.security.AccessController.doPrivileged( - new GetPropertyAction("java.version")); - password = java.security.AccessController.doPrivileged( - new GetPropertyAction("ftp.protocol.user", - "Java" + vers + "@")); + Properties props = GetPropertyAction.getProperties(); + String vers = props.getProperty("java.version"); + password = props.getProperty("ftp.protocol.user", + "Java" + vers + "@"); } try { ftp = FtpClient.create(); diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java index 42f692c3738..b6168d0c2c5 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java @@ -25,9 +25,10 @@ package sun.net.www.protocol.http; -import sun.net.www.*; import java.util.Iterator; import java.util.HashMap; +import sun.net.www.*; +import sun.security.action.GetPropertyAction; /** * This class is used to parse the information in WWW-Authenticate: and Proxy-Authenticate: @@ -93,8 +94,7 @@ public class AuthenticationHeader { } static { - authPref = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.auth.preference")); + authPref = GetPropertyAction.getProperty("http.auth.preference"); // http.auth.preference can be set to SPNEGO or Kerberos. // In fact they means "Negotiate with SPNEGO" and "Negotiate with diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 5754c047219..ebabc26182e 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -52,7 +52,6 @@ import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; import java.io.*; -import java.net.*; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -78,12 +77,15 @@ import java.text.SimpleDateFormat; import java.util.TimeZone; import java.net.MalformedURLException; import java.nio.ByteBuffer; +import java.util.Properties; import static sun.net.www.protocol.http.AuthScheme.BASIC; import static sun.net.www.protocol.http.AuthScheme.DIGEST; import static sun.net.www.protocol.http.AuthScheme.NTLM; import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE; import static sun.net.www.protocol.http.AuthScheme.KERBEROS; import static sun.net.www.protocol.http.AuthScheme.UNKNOWN; +import sun.security.action.GetIntegerAction; +import sun.security.action.GetPropertyAction; /** * A class to represent an HTTP connection to a remote object. @@ -205,46 +207,38 @@ public class HttpURLConnection extends java.net.HttpURLConnection { }; static { - maxRedirects = java.security.AccessController.doPrivileged( - new sun.security.action.GetIntegerAction( - "http.maxRedirects", defaultmaxRedirects)).intValue(); - version = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("java.version")); - String agent = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.agent")); + Properties props = GetPropertyAction.getProperties(); + maxRedirects = GetIntegerAction.getProperty("http.maxRedirects", + defaultmaxRedirects); + version = props.getProperty("java.version"); + String agent = props.getProperty("http.agent"); if (agent == null) { agent = "Java/"+version; } else { agent = agent + " Java/"+version; } userAgent = agent; - validateProxy = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "http.auth.digest.validateProxy")).booleanValue(); - validateServer = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "http.auth.digest.validateServer")).booleanValue(); + validateProxy = Boolean.parseBoolean( + props.getProperty("http.auth.digest.validateProxy")); + validateServer = Boolean.parseBoolean( + props.getProperty("http.auth.digest.validateServer")); - enableESBuffer = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "sun.net.http.errorstream.enableBuffering")).booleanValue(); - timeout4ESBuffer = java.security.AccessController.doPrivileged( - new sun.security.action.GetIntegerAction( - "sun.net.http.errorstream.timeout", 300)).intValue(); + enableESBuffer = Boolean.parseBoolean( + props.getProperty("sun.net.http.errorstream.enableBuffering")); + timeout4ESBuffer = GetIntegerAction + .getProperty("sun.net.http.errorstream.timeout", 300); if (timeout4ESBuffer <= 0) { timeout4ESBuffer = 300; // use the default } - bufSize4ES = java.security.AccessController.doPrivileged( - new sun.security.action.GetIntegerAction( - "sun.net.http.errorstream.bufferSize", 4096)).intValue(); + bufSize4ES = GetIntegerAction + .getProperty("sun.net.http.errorstream.bufferSize", 4096); if (bufSize4ES <= 0) { bufSize4ES = 4096; // use the default } - allowRestrictedHeaders = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "sun.net.http.allowRestrictedHeaders")).booleanValue(); + allowRestrictedHeaders = Boolean.parseBoolean( + props.getProperty("sun.net.http.allowRestrictedHeaders")); if (!allowRestrictedHeaders) { restrictedHeaderSet = new HashSet<>(restrictedHeaders.length); for (int i=0; i < restrictedHeaders.length; i++) { diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java index 3aecc419cb2..437c3969148 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java @@ -41,7 +41,6 @@ import java.security.Principal; import java.security.cert.*; import java.util.StringTokenizer; import java.util.Vector; -import java.security.AccessController; import javax.security.auth.x500.X500Principal; @@ -139,8 +138,8 @@ final class HttpsClient extends HttpClient // If ciphers are assigned, sort them into an array. // String ciphers []; - String cipherString = AccessController.doPrivileged( - new GetPropertyAction("https.cipherSuites")); + String cipherString = + GetPropertyAction.getProperty("https.cipherSuites"); if (cipherString == null || "".equals(cipherString)) { ciphers = null; @@ -163,8 +162,8 @@ final class HttpsClient extends HttpClient // If protocols are assigned, sort them into an array. // String protocols []; - String protocolString = AccessController.doPrivileged( - new GetPropertyAction("https.protocols")); + String protocolString = + GetPropertyAction.getProperty("https.protocols"); if (protocolString == null || "".equals(protocolString)) { protocols = null; @@ -184,8 +183,7 @@ final class HttpsClient extends HttpClient } private String getUserAgent() { - String userAgent = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("https.agent")); + String userAgent = GetPropertyAction.getProperty("https.agent"); if (userAgent == null || userAgent.length() == 0) { userAgent = "JSSE"; } diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java index cde9d438714..f58ce457f7a 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java @@ -32,10 +32,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.security.AccessController; import java.security.Permission; -import java.security.PrivilegedAction; -import java.util.List; import jdk.internal.jimage.ImageLocation; import jdk.internal.jimage.ImageReader; @@ -45,6 +42,7 @@ import jdk.internal.loader.URLClassPath; import jdk.internal.loader.Resource; import sun.net.www.ParseUtil; import sun.net.www.URLConnection; +import sun.security.action.GetPropertyAction; /** * URLConnection implementation that can be used to connect to resources @@ -163,11 +161,7 @@ public class JavaRuntimeURLConnection extends URLConnection { public Permission getPermission() throws IOException { Permission p = permission; if (p == null) { - // using lambda expression here leads to recursive initialization - PrivilegedAction pa = new PrivilegedAction() { - public String run() { return System.getProperty("java.home"); } - }; - String home = AccessController.doPrivileged(pa); + String home = GetPropertyAction.getProperty("java.home"); p = new FilePermission(home + File.separator + "-", "read"); permission = p; } diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java index fbcddcb826b..81139707655 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java @@ -40,6 +40,7 @@ import java.net.MalformedURLException; import java.net.URLStreamHandler; import java.io.InputStream; import java.io.IOException; +import sun.security.action.GetPropertyAction; public class Handler extends URLStreamHandler { static URL base; @@ -54,12 +55,10 @@ public class Handler extends URLStreamHandler { URLConnection uc = null; URL ru; - Boolean tmp = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction("newdoc.localonly")); - boolean localonly = tmp.booleanValue(); + boolean localonly = Boolean.parseBoolean( + GetPropertyAction.getProperty("newdoc.localonly")); - String docurl = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("doc.url")); + String docurl = GetPropertyAction.getProperty("doc.url"); String file = u.getFile(); if (!localonly) { diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index 671fe79efcc..8a287bc2839 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -1019,9 +1019,8 @@ public class FileChannelImpl if (!propertyChecked) { synchronized (FileChannelImpl.class) { if (!propertyChecked) { - String value = AccessController.doPrivileged( - new GetPropertyAction( - "sun.nio.ch.disableSystemWideOverlappingFileLockCheck")); + String value = GetPropertyAction.getProperty( + "sun.nio.ch.disableSystemWideOverlappingFileLockCheck"); isSharedFileLockTable = ((value == null) || value.equals("false")); propertyChecked = true; } diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java index 062ce35468e..9a5c4dcb6f8 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java @@ -33,6 +33,7 @@ import java.util.*; import java.security.AccessController; import java.security.PrivilegedAction; import sun.net.ExtendedOptionsImpl; +import sun.security.action.GetPropertyAction; public class Net { @@ -382,13 +383,8 @@ public class Net { } public static boolean isFastTcpLoopbackRequested() { - String loopbackProp = java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty("jdk.net.useFastTcpLoopback"); - } - }); + String loopbackProp = + GetPropertyAction.getProperty("jdk.net.useFastTcpLoopback"); boolean enable; if ("".equals(loopbackProp)) { enable = true; @@ -647,16 +643,9 @@ public class Net { int availLevel = isExclusiveBindAvailable(); if (availLevel >= 0) { String exclBindProp = - java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty( - "sun.net.useExclusiveBind"); - } - }); + GetPropertyAction.getProperty("sun.net.useExclusiveBind"); if (exclBindProp != null) { - exclusiveBind = exclBindProp.length() == 0 ? + exclusiveBind = exclBindProp.isEmpty() ? true : Boolean.parseBoolean(exclBindProp); } else if (availLevel == 1) { exclusiveBind = true; diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/Util.java b/jdk/src/java.base/share/classes/sun/nio/ch/Util.java index af89eca4544..e71e628ede1 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/Util.java @@ -64,13 +64,7 @@ public class Util { * for potential future-proofing. */ private static long getMaxCachedBufferSize() { - String s = java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty("jdk.nio.maxCachedBufferSize"); - } - }); + String s = GetPropertyAction.getProperty("jdk.nio.maxCachedBufferSize"); if (s != null) { try { long m = Long.parseLong(s); @@ -471,8 +465,7 @@ public class Util { if (bugLevel == null) { if (!jdk.internal.misc.VM.isBooted()) return false; - String value = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.ch.bugLevel")); + String value = GetPropertyAction.getProperty("sun.nio.ch.bugLevel"); bugLevel = (value != null) ? value : ""; } return bugLevel.equals(bl); diff --git a/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template b/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template index dd4d3994240..2ad055e50ec 100644 --- a/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template +++ b/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template @@ -34,8 +34,7 @@ import java.nio.charset.spi.CharsetProvider; import java.util.Iterator; import java.util.Locale; import java.util.Map; -import java.security.AccessController; -import java.security.PrivilegedAction; +import sun.security.action.GetPropertyAction; public class StandardCharsets extends CharsetProvider { @@ -201,15 +200,7 @@ public class StandardCharsets extends CharsetProvider { } private static String getProperty(String key) { - // this method may be called during initialization of - // system class loader and thus not using lambda - return AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty(key); - } - }); + return GetPropertyAction.getProperty(key); } diff --git a/jdk/src/java.base/share/classes/sun/nio/fs/Util.java b/jdk/src/java.base/share/classes/sun/nio/fs/Util.java index 2d5c8cb6443..45d90b99222 100644 --- a/jdk/src/java.base/share/classes/sun/nio/fs/Util.java +++ b/jdk/src/java.base/share/classes/sun/nio/fs/Util.java @@ -28,8 +28,7 @@ package sun.nio.fs; import java.util.*; import java.nio.file.*; import java.nio.charset.Charset; -import java.security.*; -import sun.security.action.*; +import sun.security.action.GetPropertyAction; /** * Utility methods @@ -39,7 +38,7 @@ class Util { private Util() { } private static final Charset jnuEncoding = Charset.forName( - AccessController.doPrivileged(new GetPropertyAction("sun.jnu.encoding"))); + GetPropertyAction.getProperty("sun.jnu.encoding")); /** * Returns {@code Charset} corresponding to the sun.jnu.encoding property diff --git a/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java b/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java index ff2b2019b48..c454b431861 100644 --- a/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java +++ b/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java @@ -25,6 +25,8 @@ package sun.security.action; +import java.security.AccessController; + /** * A convenience class for retrieving the integer value of a system property * as a privileged action. @@ -67,7 +69,7 @@ public class GetIntegerAction implements java.security.PrivilegedAction { private String theProp; private int defaultVal; - private boolean defaultSet = false; + private boolean defaultSet; /** * Constructor that takes the name of the system property whose integer @@ -110,4 +112,39 @@ public class GetIntegerAction return defaultVal; return value; } + + /** + * Convenience method to get a property without going through doPrivileged + * if no security manager is present. This is unsafe for inclusion in a + * public API but allowable here since this class is now encapsulated. + * + * @param theProp the name of the system property. + */ + public static Integer getProperty(String theProp) { + if (System.getSecurityManager() == null) { + return Integer.getInteger(theProp); + } else { + return AccessController.doPrivileged( + new GetIntegerAction(theProp)); + } + } + + /** + * Convenience method to get a property without going through doPrivileged + * if no security manager is present. This is unsafe for inclusion in a + * public API but allowable here since this class is now encapsulated. + * + * @param theProp the name of the system property. + * @param defaultVal the default value. + */ + public static Integer getProperty(String theProp, int defaultVal) { + Integer value; + if (System.getSecurityManager() == null) { + value = Integer.getInteger(theProp); + } else { + value = AccessController.doPrivileged( + new GetIntegerAction(theProp)); + } + return (value != null) ? value : defaultVal; + } } diff --git a/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java b/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java index 95a113c3bef..bba172b06bc 100644 --- a/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java +++ b/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java @@ -25,6 +25,10 @@ package sun.security.action; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Properties; + /** * A convenience class for retrieving the string value of a system * property as a privileged action. @@ -46,8 +50,7 @@ package sun.security.action; * @since 1.2 */ -public class GetPropertyAction - implements java.security.PrivilegedAction { +public class GetPropertyAction implements PrivilegedAction { private String theProp; private String defaultVal; @@ -84,4 +87,57 @@ public class GetPropertyAction String value = System.getProperty(theProp); return (value == null) ? defaultVal : value; } + + /** + * Convenience method to get a property without going through doPrivileged + * if no security manager is present. This is unsafe for inclusion in a + * public API but allowable here since this class is now encapsulated. + * + * @param theProp the name of the system property. + */ + public static String getProperty(String theProp) { + if (System.getSecurityManager() == null) { + return System.getProperty(theProp); + } else { + return AccessController.doPrivileged( + new GetPropertyAction(theProp)); + } + } + + /** + * Convenience method to get a property without going through doPrivileged + * if no security manager is present. This is unsafe for inclusion in a + * public API but allowable here since this class is now encapsulated. + * + * @param theProp the name of the system property. + * @param defaultVal the default value. + */ + public static String getProperty(String theProp, String defaultVal) { + if (System.getSecurityManager() == null) { + return System.getProperty(theProp, defaultVal); + } else { + return AccessController.doPrivileged( + new GetPropertyAction(theProp, defaultVal)); + } + } + + /** + * Convenience method to call System.getProperties without + * having to go through doPrivileged if no security manager is present. + * This is unsafe for inclusion in a public API but allowable here since + * this class is now encapsulated. + */ + public static Properties getProperties() { + if (System.getSecurityManager() == null) { + return System.getProperties(); + } else { + return AccessController.doPrivileged( + new PrivilegedAction() { + public Properties run() { + return System.getProperties(); + } + } + ); + } + } } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java b/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java index 72797aea18b..731f6b13e45 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java @@ -70,8 +70,7 @@ public class DSAKeyFactory extends KeyFactorySpi { * By default this is false. * This incompatibility was introduced by 4532506. */ - String prop = AccessController.doPrivileged - (new GetPropertyAction(SERIAL_PROP, null)); + String prop = GetPropertyAction.getProperty(SERIAL_PROP); SERIAL_INTEROP = "true".equalsIgnoreCase(prop); } diff --git a/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java b/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java index d869a8aaca4..d3497aea557 100644 --- a/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java +++ b/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java @@ -84,9 +84,8 @@ public final class RSAKeyFactory extends KeyFactorySpi { public static final int MAX_RESTRICTED_EXPLEN = 64; private static final boolean restrictExpLen = - "true".equalsIgnoreCase(AccessController.doPrivileged( - new GetPropertyAction( - "sun.security.rsa.restrictRSAExponent", "true"))); + "true".equalsIgnoreCase(GetPropertyAction.getProperty( + "sun.security.rsa.restrictRSAExponent", "true")); // instance used for static translateKey(); private static final RSAKeyFactory INSTANCE = new RSAKeyFactory(); diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java b/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java index 8da221961a0..8f849f8d54f 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java @@ -50,10 +50,7 @@ public interface ClientKeyExchangeService { providers = new HashMap<>(); static { - final String key = "java.home"; - String path = AccessController.doPrivileged( - new GetPropertyAction(key), null, - new PropertyPermission(key, "read")); + String path = GetPropertyAction.getProperty("java.home"); ServiceLoader sc = AccessController.doPrivileged( (PrivilegedAction>) diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java index 494dd3257ba..c05505edf4a 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java @@ -26,7 +26,6 @@ package sun.security.ssl; import java.io.PrintStream; -import java.security.AccessController; import java.util.Locale; import sun.security.util.HexDumpEncoder; @@ -46,8 +45,7 @@ public class Debug { private static String args; static { - args = java.security.AccessController.doPrivileged( - new GetPropertyAction("javax.net.debug", "")); + args = GetPropertyAction.getProperty("javax.net.debug", ""); args = args.toLowerCase(Locale.ENGLISH); if (args.equals("help")) { Help(); @@ -184,8 +182,7 @@ public class Debug { */ static boolean getBooleanProperty(String propName, boolean defaultValue) { // if set, require value of either true or false - String b = AccessController.doPrivileged( - new GetPropertyAction(propName)); + String b = GetPropertyAction.getProperty(propName); if (b == null) { return defaultValue; } else if (b.equalsIgnoreCase("false")) { diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java index 903f6fb376a..f3384c5b746 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java @@ -656,8 +656,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { // the provider service. Instead, please handle the initialization // exception in the caller's constructor. static { - String property = AccessController.doPrivileged( - new GetPropertyAction(PROPERTY_NAME)); + String property = GetPropertyAction.getProperty(PROPERTY_NAME); if (property != null && property.length() != 0) { // remove double quote marks from beginning/end of the property if (property.length() > 1 && property.charAt(0) == '"' && diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java index 32e434aa6b4..5ce147a3af3 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java @@ -119,8 +119,8 @@ final class ServerHandshaker extends Handshaker { private long statusRespTimeout; static { - String property = AccessController.doPrivileged( - new GetPropertyAction("jdk.tls.ephemeralDHKeySize")); + String property = + GetPropertyAction.getProperty("jdk.tls.ephemeralDHKeySize"); if (property == null || property.length() == 0) { useLegacyEphemeralDHKeys = false; useSmartEphemeralDHKeys = false; diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java b/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java index b618ab31a13..3e21616e48e 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java @@ -73,8 +73,8 @@ final class StatusResponseManager { DEFAULT_CACHE_LIFETIME)); cacheLifetime = life > 0 ? life : 0; - String uriStr = AccessController.doPrivileged( - new GetPropertyAction("jdk.tls.stapling.responderURI")); + String uriStr = + GetPropertyAction.getProperty("jdk.tls.stapling.responderURI"); URI tmpURI; try { tmpURI = ((uriStr != null && !uriStr.isEmpty()) ? diff --git a/jdk/src/java.base/share/classes/sun/security/util/Debug.java b/jdk/src/java.base/share/classes/sun/security/util/Debug.java index 35ce8d66348..514608dc73c 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/Debug.java +++ b/jdk/src/java.base/share/classes/sun/security/util/Debug.java @@ -29,6 +29,7 @@ import java.math.BigInteger; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.Locale; +import sun.security.action.GetPropertyAction; /** * A utility class for debuging. @@ -42,13 +43,10 @@ public class Debug { private static String args; static { - args = java.security.AccessController.doPrivileged - (new sun.security.action.GetPropertyAction - ("java.security.debug")); + args = GetPropertyAction.getProperty("java.security.debug"); - String args2 = java.security.AccessController.doPrivileged - (new sun.security.action.GetPropertyAction - ("java.security.auth.debug")); + String args2 = + GetPropertyAction.getProperty("java.security.auth.debug"); if (args == null) { args = args2; diff --git a/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java b/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java index 10cbbdceee1..90389c73252 100644 --- a/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java +++ b/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java @@ -27,6 +27,7 @@ package sun.util.calendar; import java.security.AccessController; import java.util.TimeZone; +import sun.security.action.GetPropertyAction; /** * @@ -142,8 +143,8 @@ public class LocalGregorianCalendar extends BaseCalendar { } // Append an era to the predefined eras if it's given by the property. - String prop = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("jdk.calendar.japanese.supplemental.era")); + String prop = GetPropertyAction + .getProperty("jdk.calendar.japanese.supplemental.era"); if (prop != null) { Era era = parseEraEntry(prop); if (era != null) { diff --git a/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index 365e0e7967c..26fbb59a9f4 100644 --- a/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -245,11 +245,8 @@ public final class ZoneInfoFile { }; static { - String oldmapping = AccessController.doPrivileged( - new GetPropertyAction("sun.timezone.ids.oldmapping", "false")).toLowerCase(Locale.ROOT); - USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true")); - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { + USE_OLDMAPPING = AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { try { String libDir = System.getProperty("java.home") + File.separator + "lib"; try (DataInputStream dis = new DataInputStream( @@ -260,7 +257,9 @@ public final class ZoneInfoFile { } catch (Exception x) { throw new Error(x); } - return null; + String oldmapping = System.getProperty("sun.timezone.ids.oldmapping", "false") + .toLowerCase(Locale.ROOT); + return (oldmapping.equals("yes") || oldmapping.equals("true")); } }); } diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index e19a6c8c531..75f235c73e7 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -25,7 +25,6 @@ package sun.util.locale.provider; -import java.security.AccessController; import java.text.spi.BreakIteratorProvider; import java.text.spi.CollatorProvider; import java.text.spi.DateFormatProvider; @@ -47,6 +46,7 @@ import java.util.spi.CurrencyNameProvider; import java.util.spi.LocaleNameProvider; import java.util.spi.LocaleServiceProvider; import java.util.spi.TimeZoneNameProvider; +import sun.security.action.GetPropertyAction; import sun.util.spi.CalendarProvider; /** @@ -116,8 +116,7 @@ public abstract class LocaleProviderAdapter { adapterCache = new ConcurrentHashMap<>(); static { - String order = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("java.locale.providers")); + String order = GetPropertyAction.getProperty("java.locale.providers"); List typeList = new ArrayList<>(); // Check user specified adapter preference diff --git a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java index 8b4177e3fde..140473283c8 100644 --- a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java +++ b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java @@ -28,7 +28,6 @@ package sun.nio.fs; import java.nio.file.*; import java.io.IOException; import java.util.*; -import java.security.AccessController; import sun.security.action.GetPropertyAction; import static sun.nio.fs.SolarisNativeDispatcher.*; @@ -43,8 +42,7 @@ class SolarisFileSystem extends UnixFileSystem { super(provider, dir); // check os.version - String osversion = AccessController - .doPrivileged(new GetPropertyAction("os.version")); + String osversion = GetPropertyAction.getProperty("os.version"); String[] vers = Util.split(osversion, '.'); assert vers.length >= 2; int majorVersion = Integer.parseInt(vers[0]); diff --git a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java index 4fcb617a200..affdfb96c7f 100644 --- a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java +++ b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java @@ -29,7 +29,6 @@ import java.nio.file.*; import java.nio.file.attribute.*; import java.nio.file.spi.FileTypeDetector; import java.io.IOException; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -85,8 +84,8 @@ public class SolarisFileSystemProvider extends UnixFileSystemProvider { @Override FileTypeDetector getFileTypeDetector() { - Path userMimeTypes = Paths.get(AccessController.doPrivileged( - new GetPropertyAction("user.home")), ".mime.types"); + Path userMimeTypes = Paths.get( + GetPropertyAction.getProperty("user.home"), ".mime.types"); Path etcMimeTypes = Paths.get("/etc/mime.types"); return chain(new GioFileTypeDetector(), diff --git a/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java b/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java index c0ca02dd4ad..c829994cc85 100644 --- a/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java +++ b/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java @@ -25,7 +25,7 @@ package java.io; -import java.security.AccessController; +import java.util.Properties; import sun.security.action.GetPropertyAction; @@ -36,12 +36,10 @@ class UnixFileSystem extends FileSystem { private final String javaHome; public UnixFileSystem() { - slash = AccessController.doPrivileged( - new GetPropertyAction("file.separator")).charAt(0); - colon = AccessController.doPrivileged( - new GetPropertyAction("path.separator")).charAt(0); - javaHome = AccessController.doPrivileged( - new GetPropertyAction("java.home")); + Properties props = GetPropertyAction.getProperties(); + slash = props.getProperty("file.separator").charAt(0); + colon = props.getProperty("path.separator").charAt(0); + javaHome = props.getProperty("java.home"); } diff --git a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java index 5f9a546f4bd..8a1b8ca085e 100644 --- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java +++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java @@ -46,8 +46,10 @@ import static java.security.AccessController.doPrivileged; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.Properties; import jdk.internal.misc.JavaIOFileDescriptorAccess; import jdk.internal.misc.SharedSecrets; +import sun.security.action.GetPropertyAction; /** * java.lang.Process subclass in the UNIX environment. @@ -123,11 +125,9 @@ final class ProcessImpl extends Process { } String helperPath() { - return AccessController.doPrivileged( - (PrivilegedAction) () -> - helperPath(System.getProperty("java.home"), - System.getProperty("os.arch")) - ); + Properties props = GetPropertyAction.getProperties(); + return helperPath(props.getProperty("java.home"), + props.getProperty("os.arch")); } LaunchMechanism launchMechanism() { @@ -159,9 +159,7 @@ final class ProcessImpl extends Process { } static Platform get() { - String osName = AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("os.name") - ); + String osName = GetPropertyAction.getProperty("os.name"); if (osName.equals("Linux")) { return LINUX; } if (osName.contains("OS X")) { return BSD; } diff --git a/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java b/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java index ad62c582691..dd1a6548d6a 100644 --- a/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java +++ b/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java @@ -24,7 +24,7 @@ */ package java.net; -import java.security.AccessController; +import sun.security.action.GetPropertyAction; /** * This class defines a factory for creating DatagramSocketImpls. It defaults @@ -40,8 +40,7 @@ class DefaultDatagramSocketImplFactory { static { String prefix = null; try { - prefix = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("impl.prefix", null)); + prefix = GetPropertyAction.getProperty("impl.prefix", null); if (prefix != null) prefixImplClass = Class.forName("java.net."+prefix+"DatagramSocketImpl"); } catch (Exception e) { diff --git a/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java b/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java index 2b1c3fd841e..a9f15a617f0 100644 --- a/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java +++ b/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java @@ -34,7 +34,6 @@ import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintStream; -import java.security.AccessController; import sun.net.sdp.SdpSupport; import sun.security.action.GetPropertyAction; @@ -57,8 +56,7 @@ public class SdpProvider extends NetHooks.Provider { public SdpProvider() { // if this property is not defined then there is nothing to do. - String file = AccessController.doPrivileged( - new GetPropertyAction("com.sun.sdp.conf")); + String file = GetPropertyAction.getProperty("com.sun.sdp.conf"); if (file == null) { this.enabled = false; this.rules = null; @@ -77,8 +75,7 @@ public class SdpProvider extends NetHooks.Provider { // check if debugging is enabled PrintStream out = null; - String logfile = AccessController.doPrivileged( - new GetPropertyAction("com.sun.sdp.debug")); + String logfile = GetPropertyAction.getProperty("com.sun.sdp.debug"); if (logfile != null) { out = System.out; if (logfile.length() > 0) { diff --git a/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index 0e067d0681f..f205eaf7545 100644 --- a/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -39,6 +39,7 @@ import sun.net.www.HeaderParser; import sun.net.www.protocol.http.AuthenticationInfo; import sun.net.www.protocol.http.AuthScheme; import sun.net.www.protocol.http.HttpURLConnection; +import sun.security.action.GetPropertyAction; /** * NTLMAuthentication: @@ -73,12 +74,9 @@ public class NTLMAuthentication extends AuthenticationInfo { NTLMAuthenticationCallback.getNTLMAuthenticationCallback(); private String hostname; - private static String defaultDomain; /* Domain to use if not specified by user */ - - static { - defaultDomain = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.auth.ntlm.domain", "")); - }; + /* Domain to use if not specified by user */ + private static String defaultDomain = + GetPropertyAction.getProperty("http.auth.ntlm.domain", ""); public static boolean supportsTransparentAuth () { return false; @@ -143,8 +141,7 @@ public class NTLMAuthentication extends AuthenticationInfo { password = pw.getPassword(); init0(); try { - String version = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("ntlm.version")); + String version = GetPropertyAction.getProperty("ntlm.version"); client = new Client(version, hostname, username, ntdomain, password); } catch (NTLMException ne) { try { diff --git a/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java index 7a0ce392299..9018f0fe6a0 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java +++ b/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java @@ -26,7 +26,6 @@ package sun.nio.ch; import java.nio.channels.spi.AsynchronousChannelProvider; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -60,8 +59,7 @@ public class DefaultAsynchronousChannelProvider { * Returns the default AsynchronousChannelProvider. */ public static AsynchronousChannelProvider create() { - String osname = AccessController - .doPrivileged(new GetPropertyAction("os.name")); + String osname = GetPropertyAction.getProperty("os.name"); if (osname.equals("SunOS")) return createProvider("sun.nio.ch.SolarisAsynchronousChannelProvider"); if (osname.equals("Linux")) diff --git a/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java index 3307c40d8c5..f8c31b5ac94 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java +++ b/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java @@ -31,7 +31,6 @@ import java.net.*; import java.util.concurrent.*; import java.io.IOException; import java.io.FileDescriptor; -import java.security.AccessController; import sun.net.NetHooks; import sun.security.action.GetPropertyAction; @@ -47,8 +46,8 @@ class UnixAsynchronousSocketChannelImpl private static final boolean disableSynchronousRead; static { - String propValue = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.ch.disableSynchronousRead", "false")); + String propValue = GetPropertyAction + .getProperty("sun.nio.ch.disableSynchronousRead", "false"); disableSynchronousRead = (propValue.length() == 0) ? true : Boolean.valueOf(propValue); } diff --git a/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java index 595f3c6d187..62f6d5ce145 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java +++ b/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -26,7 +26,6 @@ package sun.nio.fs; import java.nio.file.spi.FileSystemProvider; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -55,8 +54,7 @@ public class DefaultFileSystemProvider { * Returns the default FileSystemProvider. */ public static FileSystemProvider create() { - String osname = AccessController - .doPrivileged(new GetPropertyAction("os.name")); + String osname = GetPropertyAction.getProperty("os.name"); if (osname.equals("SunOS")) return createProvider("sun.nio.fs.SolarisFileSystemProvider"); if (osname.equals("Linux")) diff --git a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java index d394ac10173..7cf295b0d6d 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java +++ b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java @@ -31,7 +31,6 @@ import java.nio.file.spi.*; import java.io.IOException; import java.util.*; import java.util.regex.Pattern; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -57,8 +56,8 @@ abstract class UnixFileSystem // if process-wide chdir is allowed or default directory is not the // process working directory then paths must be resolved against the // default directory. - String propValue = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.fs.chdirAllowed", "false")); + String propValue = GetPropertyAction + .getProperty("sun.nio.fs.chdirAllowed", "false"); boolean chdirAllowed = (propValue.length() == 0) ? true : Boolean.valueOf(propValue); if (chdirAllowed) { diff --git a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java index 9ee66bf4169..50ccacc3d1e 100644 --- a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java +++ b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java @@ -25,8 +25,8 @@ package java.io; -import java.security.AccessController; import java.util.Locale; +import java.util.Properties; import sun.security.action.GetPropertyAction; /** @@ -42,10 +42,9 @@ class WinNTFileSystem extends FileSystem { private final char semicolon; public WinNTFileSystem() { - slash = AccessController.doPrivileged( - new GetPropertyAction("file.separator")).charAt(0); - semicolon = AccessController.doPrivileged( - new GetPropertyAction("path.separator")).charAt(0); + Properties props = GetPropertyAction.getProperties(); + slash = props.getProperty("file.separator").charAt(0); + semicolon = props.getProperty("path.separator").charAt(0); altSlash = (this.slash == '\\') ? '/' : '\\'; } diff --git a/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java b/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java index fb632a4a816..c12378da67d 100644 --- a/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java +++ b/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java @@ -24,8 +24,7 @@ */ package java.net; -import java.security.AccessController; -import java.security.PrivilegedAction; +import java.util.Properties; import sun.security.action.GetPropertyAction; /** @@ -57,12 +56,11 @@ class DefaultDatagramSocketImplFactory static { Class prefixImplClassLocal = null; + Properties props = GetPropertyAction.getProperties(); preferIPv4Stack = Boolean.parseBoolean( - AccessController.doPrivileged( - new GetPropertyAction("java.net.preferIPv4Stack"))); + props.getProperty("java.net.preferIPv4Stack")); - String exclBindProp = AccessController.doPrivileged( - new GetPropertyAction("sun.net.useExclusiveBind", "")); + String exclBindProp = props.getProperty("sun.net.useExclusiveBind", ""); exclusiveBind = (exclBindProp.isEmpty()) ? true : Boolean.parseBoolean(exclBindProp); @@ -70,8 +68,7 @@ class DefaultDatagramSocketImplFactory // impl.prefix String prefix = null; try { - prefix = AccessController.doPrivileged( - new GetPropertyAction("impl.prefix", null)); + prefix = props.getProperty("impl.prefix"); if (prefix != null) prefixImplClassLocal = Class.forName("java.net."+prefix+"DatagramSocketImpl"); } catch (Exception e) { diff --git a/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index 0e17de44b4c..5583842d0cb 100644 --- a/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -34,6 +34,7 @@ import sun.net.www.HeaderParser; import sun.net.www.protocol.http.AuthenticationInfo; import sun.net.www.protocol.http.AuthScheme; import sun.net.www.protocol.http.HttpURLConnection; +import sun.security.action.GetPropertyAction; /** * NTLMAuthentication: @@ -52,9 +53,8 @@ public class NTLMAuthentication extends AuthenticationInfo { private static String defaultDomain; /* Domain to use if not specified by user */ static { - defaultDomain = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.auth.ntlm.domain", - "domain")); + defaultDomain = GetPropertyAction.getProperty("http.auth.ntlm.domain", + "domain"); }; private void init0() { diff --git a/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java b/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java index 4b812d35a4d..5390b55a3ab 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java +++ b/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java @@ -27,9 +27,9 @@ package sun.nio.ch; import java.io.FileDescriptor; import java.io.IOException; -import java.security.PrivilegedAction; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.JavaIOFileDescriptorAccess; +import sun.security.action.GetPropertyAction; class FileDispatcherImpl extends FileDispatcher { @@ -119,13 +119,8 @@ class FileDispatcherImpl extends FileDispatcher { } static boolean isFastFileTransferRequested() { - String fileTransferProp = java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty("jdk.nio.enableFastFileTransfer"); - } - }); + String fileTransferProp = GetPropertyAction + .getProperty("jdk.nio.enableFastFileTransfer"); boolean enable; if ("".equals(fileTransferProp)) { enable = true; diff --git a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java index 02226053f8d..4d2d3e97c4c 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java +++ b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java @@ -27,7 +27,6 @@ package sun.nio.fs; import java.nio.file.attribute.*; import java.util.concurrent.TimeUnit; -import java.security.AccessController; import jdk.internal.misc.Unsafe; import sun.security.action.GetPropertyAction; @@ -115,8 +114,8 @@ class WindowsFileAttributes // indicates if accurate metadata is required (interesting on NTFS only) private static final boolean ensureAccurateMetadata; static { - String propValue = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.fs.ensureAccurateMetadata", "false")); + String propValue = GetPropertyAction + .getProperty("sun.nio.fs.ensureAccurateMetadata", "false"); ensureAccurateMetadata = (propValue.length() == 0) ? true : Boolean.valueOf(propValue); } From 6e1f8aab874a9667e21b1c35352685e5a3d95de9 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 21 Apr 2016 17:21:31 +0200 Subject: [PATCH 121/222] 8154853: java/util/TimeZone/OldIDMappingTest.sh fails after JDK-8154231 Reviewed-by: chegar --- .../classes/sun/util/calendar/ZoneInfoFile.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index 26fbb59a9f4..58c0c5bbe01 100644 --- a/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -245,8 +245,12 @@ public final class ZoneInfoFile { }; static { - USE_OLDMAPPING = AccessController.doPrivileged(new PrivilegedAction() { - public Boolean run() { + String oldmapping = GetPropertyAction + .getProperty("sun.timezone.ids.oldmapping", "false") + .toLowerCase(Locale.ROOT); + USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true")); + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { try { String libDir = System.getProperty("java.home") + File.separator + "lib"; try (DataInputStream dis = new DataInputStream( @@ -257,9 +261,7 @@ public final class ZoneInfoFile { } catch (Exception x) { throw new Error(x); } - String oldmapping = System.getProperty("sun.timezone.ids.oldmapping", "false") - .toLowerCase(Locale.ROOT); - return (oldmapping.equals("yes") || oldmapping.equals("true")); + return null; } }); } From d8acc2fbcf4d2a4373c7ec11fd85e4886bc1137b Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Thu, 21 Apr 2016 09:55:04 -0700 Subject: [PATCH 122/222] 8129329: sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java failed intermittently Reviewed-by: xuelei --- .../ssl/SSLContextImpl/MD2InTrustAnchor.java | 358 +++++++----------- 1 file changed, 129 insertions(+), 229 deletions(-) diff --git a/jdk/test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java b/jdk/test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java index 9d8ee1d5287..f2e06337dd3 100644 --- a/jdk/test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java +++ b/jdk/test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,106 +37,88 @@ * @run main/othervm MD2InTrustAnchor PKIX TLSv1.2 * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.2 */ - -import java.net.*; -import java.util.*; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.OutputStream; import javax.net.ssl.*; import java.security.Security; import java.security.KeyStore; import java.security.KeyFactory; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; import java.util.Base64; +import java.util.concurrent.CountDownLatch; public class MD2InTrustAnchor { - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ - - /* - * Should we run the client or server in a separate thread? - * Both sides can throw exceptions, but do you have a preference - * as to which side should be the main thread. - */ - static boolean separateServerThread = false; - /* * Certificates and key used in the test. */ - // It's a trust anchor signed with MD2 hash function. - static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + - "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" + - "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" + - "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" + - "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" + - "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" + - "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" + - "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" + - "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" + - "-----END CERTIFICATE-----"; + private static final String TRUSTED_CERT_STR = "-----BEGIN CERTIFICATE-----\n" + + "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + + "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" + + "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" + + "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" + + "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" + + "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" + + "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" + + "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" + + "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" + + "-----END CERTIFICATE-----"; // The certificate issued by above trust anchor, signed with MD5 - static String targetCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + - "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" + - "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" + - "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" + - "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" + - "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" + - "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + - "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" + - "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" + - "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" + - "yvudOlX4BkVR0l1K\n" + - "-----END CERTIFICATE-----"; + private static final String TARGET_CERT_STR = "-----BEGIN CERTIFICATE-----\n" + + "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + + "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" + + "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" + + "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" + + "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" + + "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" + + "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + + "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" + + "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" + + "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" + + "yvudOlX4BkVR0l1K\n" + + "-----END CERTIFICATE-----"; // Private key in the format of PKCS#8. - static String targetPrivateKey = - "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" + - "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" + - "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" + - "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" + - "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" + - "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" + - "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" + - "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" + - "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" + - "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" + - "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" + - "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" + - "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" + - "njWHoKY3axDQ8OU=\n"; + private static final String TARGET_PRIV_KEY_STR = "MIICdwIBADANBgkqhkiG9w0B\n" + + "AQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4F5NVEtFXCbEFcVLRjMp3AL3j\n" + + "LswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa9+uHt0Z9Wmh4wjHAZhX5Tm5x\n" + + "p4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPMKBpyzK6rusorkwpWywTyvH1s\n" + + "016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+KSH9tFt+WQbiojjz9ac49trkv\n" + + "Ufu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck5mOIYV4uZK8jfNMSQ8v0tFEe\n" + + "IPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+HaY3d76hR5qly+Ys+Ww0CQQDj\n" + + "eOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ6t0v/xryVIdvOYcRBvKnqEog\n" + + "OH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7ez3TDpU9w1B0JXklcV5HddYsR\n" + + "qp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3ML11xwwJBAKsZ+Hur3x0tUY29\n" + + "No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDElhIM6Rqv12kwCMuQE9i7vo1o3\n" + + "WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXsekdXAA4d2d5zGI7q/aGD9SYU6\n" + + "phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRTA5kokFb+E3Gplu29tJvCUpfw\n" + + "gBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiEnjWHoKY3axDQ8OU="; - - static char passphrase[] = "passphrase".toCharArray(); + private static final char PASSPHRASE[] = "passphrase".toCharArray(); /* * Is the server ready to serve? */ - volatile static boolean serverReady = false; + private static volatile CountDownLatch sync = new CountDownLatch(1); /* * Turn on SSL debugging? */ - static boolean debug = false; + private static final boolean DEBUG = false; /* * Define the server side of the test. @@ -144,29 +126,30 @@ public class MD2InTrustAnchor { * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ - void doServerSide() throws Exception { - SSLContext context = generateSSLContext(trustedCertStr, targetCertStr, - targetPrivateKey); + private void doServerSide() throws Exception { + SSLContext context = generateSSLContext(TRUSTED_CERT_STR, TARGET_CERT_STR, + TARGET_PRIV_KEY_STR); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); - SSLServerSocket sslServerSocket = - (SSLServerSocket)sslssf.createServerSocket(serverPort); - sslServerSocket.setNeedClientAuth(true); - serverPort = sslServerSocket.getLocalPort(); + try (SSLServerSocket sslServerSocket + = (SSLServerSocket) sslssf.createServerSocket(serverPort)) { + sslServerSocket.setNeedClientAuth(true); + serverPort = sslServerSocket.getLocalPort(); + /* + * Signal Client, we're ready for his connect. + */ + System.out.println("Signal server ready"); + sync.countDown(); - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; + System.out.println("Waiting for client connection"); + try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept()) { + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); - SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - - sslIS.read(); - sslOS.write('A'); - sslOS.flush(); - - sslSocket.close(); + sslIS.read(); + sslOS.write('A'); + sslOS.flush(); + } + } } /* @@ -175,33 +158,31 @@ public class MD2InTrustAnchor { * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ - void doClientSide() throws Exception { + private void doClientSide() throws Exception { /* * Wait for server to get started. */ - while (!serverReady) { - Thread.sleep(50); - } + System.out.println("Waiting for server ready"); + sync.await(); - SSLContext context = generateSSLContext(trustedCertStr, targetCertStr, - targetPrivateKey); + SSLContext context = generateSSLContext(TRUSTED_CERT_STR, TARGET_CERT_STR, + TARGET_PRIV_KEY_STR); SSLSocketFactory sslsf = context.getSocketFactory(); - SSLSocket sslSocket = - (SSLSocket)sslsf.createSocket("localhost", serverPort); + System.out.println("Connect to server on port: " + serverPort); + try (SSLSocket sslSocket + = (SSLSocket) sslsf.createSocket("localhost", serverPort)) { + // enable the specified TLS protocol + sslSocket.setEnabledProtocols(new String[]{tlsProtocol}); - // enable the specified TLS protocol - sslSocket.setEnabledProtocols(new String[] {tlsProtocol}); + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - - sslOS.write('B'); - sslOS.flush(); - sslIS.read(); - - sslSocket.close(); + sslOS.write('B'); + sslOS.flush(); + sslIS.read(); + } } /* @@ -240,10 +221,10 @@ public class MD2InTrustAnchor { if (keyCertStr != null) { // generate the private key. PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keySpecStr)); + Base64.getMimeDecoder().decode(keySpecStr)); KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); + RSAPrivateKey priKey + = (RSAPrivateKey) kf.generatePrivate(priKeySpec); // generate certificate chain is = new ByteArrayInputStream(keyCertStr.getBytes()); @@ -257,7 +238,7 @@ public class MD2InTrustAnchor { chain[0] = keyCert; // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); + ks.setKeyEntry("Whatever", priKey, PASSPHRASE, chain); } // create SSL context @@ -267,7 +248,7 @@ public class MD2InTrustAnchor { SSLContext ctx = SSLContext.getInstance(tlsProtocol); if (keyCertStr != null && !keyCertStr.isEmpty()) { KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); + kmf.init(ks, PASSPHRASE); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); ks = null; @@ -278,12 +259,10 @@ public class MD2InTrustAnchor { return ctx; } - // use any free port by default - volatile int serverPort = 0; + private volatile int serverPort = 0; - volatile Exception serverException = null; - volatile Exception clientException = null; + private volatile Exception serverException = null; public static void main(String[] args) throws Exception { // MD5 is used in this test case, don't disable MD5 algorithm. @@ -292,140 +271,61 @@ public class MD2InTrustAnchor { Security.setProperty("jdk.tls.disabledAlgorithms", "SSLv3, RC4, DH keySize < 768"); - if (debug) + if (DEBUG) { System.setProperty("javax.net.debug", "all"); + } /* * Get the customized arguments. */ parseArguments(args); - /* * Start the tests. */ - new MD2InTrustAnchor(); + new MD2InTrustAnchor().runTest(); } - Thread clientThread = null; - Thread serverThread = null; + private Thread serverThread = null; /* - * Primary constructor, used to drive remainder of the test. + * Used to drive remainder of the test. * * Fork off the other side, then do your work. */ - MD2InTrustAnchor() throws Exception { - try { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - } catch (Exception e) { - // swallow for now. Show later - } + public void runTest() throws Exception { + startServerThread(); + doClientSide(); /* * Wait for other side to close down. */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } + serverThread.join(); - /* - * When we get here, the test is pretty much over. - * Which side threw the error? - */ - Exception local; - Exception remote; - String whichRemote; - - if (separateServerThread) { - remote = serverException; - local = clientException; - whichRemote = "server"; - } else { - remote = clientException; - local = serverException; - whichRemote = "client"; - } - - /* - * If both failed, return the curthread's exception, but also - * print the remote side Exception - */ - if ((local != null) && (remote != null)) { - System.out.println(whichRemote + " also threw:"); - remote.printStackTrace(); - System.out.println(); - throw local; - } - - if (remote != null) { - throw remote; - } - - if (local != null) { - throw local; + if (serverException != null) { + throw serverException; } } - void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; - } + private void startServerThread() { + serverThread = new Thread() { + @Override + public void run() { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died..."); + e.printStackTrace(System.out); + serverException = e; + sync.countDown(); } - }; - serverThread.start(); - } else { - try { - doServerSide(); - } catch (Exception e) { - serverException = e; - } finally { - serverReady = true; } - } - } + }; - void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } - } - }; - clientThread.start(); - } else { - try { - doClientSide(); - } catch (Exception e) { - clientException = e; - } - } + serverThread.start(); } } From c2f3c9f0db5bc8f64eb3f6757edf76b51dccd92f Mon Sep 17 00:00:00 2001 From: Alexander Stepanov Date: Thu, 21 Apr 2016 20:08:18 +0300 Subject: [PATCH 123/222] 8154762: [TEST] add some tests according to JDK-8132138 Reviewed-by: ssadetsky, serb --- .../beans/Introspector/BeanPropertyTest.java | 988 ++++++++++++++++++ 1 file changed, 988 insertions(+) create mode 100644 jdk/test/java/beans/Introspector/BeanPropertyTest.java diff --git a/jdk/test/java/beans/Introspector/BeanPropertyTest.java b/jdk/test/java/beans/Introspector/BeanPropertyTest.java new file mode 100644 index 00000000000..0344f378cc6 --- /dev/null +++ b/jdk/test/java/beans/Introspector/BeanPropertyTest.java @@ -0,0 +1,988 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.beans.BeanInfo; +import java.beans.BeanProperty; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; + +import java.util.Arrays; + + +/** + * @test + * @bug 8132703 8132163 8132732 8132973 8154756 8132888 + * @summary Some check for BeanProperty annotation + * @author a.stepanov + * @run main BeanPropertyTest + */ + + +public class BeanPropertyTest { + + private final static String DESCRIPTION = "TEST"; + private final static boolean BOUND = true; + private final static boolean EXPERT = false; + private final static boolean HIDDEN = true; + private final static boolean PREFERRED = false; + private final static boolean REQUIRED = true; + private final static boolean UPDATE = false; + private final static String + V_NAME = "javax.swing.SwingConstants.TOP", + V_SHORT = "TOP", + V = Integer.toString(javax.swing.SwingConstants.TOP); + private final static int X = javax.swing.SwingConstants.TOP; + + private final static String DESCRIPTION_2 = "XYZ"; + + + // ---------- test cases ---------- + + public static class G01 { + + private final static String TESTCASE = "arbitrary getter name"; + + private final int x = X; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int get1() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class S01 { + + private final static String TESTCASE = "arbitrary setter name"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setXXXXX(int v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132703 + public static class G02 { + + private final static String TESTCASE = "arbitrary getter name"; + + private final int x = X; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int get() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132703 + public static class S02 { + + private final static String TESTCASE = "arbitrary setter name"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void set(int v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132703 + public static class G03 { + + private final static String TESTCASE = "arbitrary getter name"; + + private final int x = X; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int GetX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132703 + public static class S03 { + + private final static String TESTCASE = "arbitrary setter name"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void SetX(int v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132163 + public static class G04 { + + private final static String TESTCASE = "arbitrary getter return type"; + + private final int x = X; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public Object getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132163 + public static class S04 { + + private final static String TESTCASE = "arbitrary setter argument type"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(short v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class G05 { + + private final static String TESTCASE = + "annotated getter + arbitrary setter argument type"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getX() { return x; } + public void setX(short v) { x = v; } + + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132163 + public static class S05 { + + private final static String TESTCASE = + "annotated setter + arbitrary getter return type"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(int v) { x = v; } + public Object getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class G06 { + + private final static String TESTCASE = "indexed getter"; + + private final int x[] = {X, X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getX(int i) throws IndexOutOfBoundsException { + if (i < 0 || i >= x.length) { + throw new IndexOutOfBoundsException(); } + return x[i]; + } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class S06 { + + private final static String TESTCASE = "indexed setter"; + + private final int x[] = {X, X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(int i, int v) throws IndexOutOfBoundsException { + if (i < 0 || i >= x.length) { + throw new IndexOutOfBoundsException(); } + x[i] = v; + } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class G07 { + + private final static String TESTCASE = + "indexed (annotated) + non-indexed getters"; + + private final int x[] = {X, X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getX(int i) throws IndexOutOfBoundsException { + if (i < 0 || i >= x.length) { + throw new IndexOutOfBoundsException(); } + return x[i]; + } + + public int[] getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class S07 { + + private final static String TESTCASE = + "indexed (annotated) + non-indexed setters"; + + private int x[] = new int[3]; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(int i, int v) throws IndexOutOfBoundsException { + if (i < 0 || i >= x.length) { + throw new IndexOutOfBoundsException(); } + x[i] = v; + } + + public void setX(int a[]) { x = Arrays.copyOf(a, a.length); } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132732 + public static class G08 { + + private final static String TESTCASE = + "non-indexed (annotated) + indexed getters"; + + private final int x[] = {X, X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int[] getX() { return x; } + + public int getX(int i) throws IndexOutOfBoundsException { + if (i < 0 || i >= x.length) { + throw new IndexOutOfBoundsException(); } + return x[i]; + } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132732 + public static class S08 { + + private final static String TESTCASE = + "non-indexed (annotated) + indexed setters"; + + private int x[] = new int[3]; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(int a[]) { x = Arrays.copyOf(a, a.length); } + + public void setX(int i, int v) throws IndexOutOfBoundsException { + if (i < 0 || i >= x.length) { + throw new IndexOutOfBoundsException(); } + x[i] = v; + } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132732 + public static class G09 { + + private final static String TESTCASE = "two annotated getters"; + + private final int x[] = {X, X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int[] getX() { return x; } + + @BeanProperty( + description = DESCRIPTION_2, + bound = !BOUND, + expert = !EXPERT, + hidden = !HIDDEN, + preferred = !PREFERRED, + required = !REQUIRED, + visualUpdate = !UPDATE) + public int getX(int i) throws IndexOutOfBoundsException { + if (i < 0 || i >= x.length) { + throw new IndexOutOfBoundsException(); } + return x[i]; + } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132732 + public static class S09 { + + private final static String TESTCASE = "two annotated setters"; + + private int x[] = new int[3]; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(int a[]) { x = Arrays.copyOf(a, a.length); } + + @BeanProperty( + description = DESCRIPTION_2, + bound = !BOUND, + expert = !EXPERT, + hidden = !HIDDEN, + preferred = !PREFERRED, + required = !REQUIRED, + visualUpdate = !UPDATE) + public void setX(int i, int v) throws IndexOutOfBoundsException { + if (i < 0 || i >= x.length) { + throw new IndexOutOfBoundsException(); } + x[i] = v; + } + + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class G10 { + + private final static String TESTCASE = + "getter + similarly named field"; + + public int prop, Prop, setProp, getProp; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getProp() { return X; } + public void setProp(int v) { prop = Prop = setProp = getProp = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class S10 { + + private final static String TESTCASE = + "setter + similarly named field"; + + public int prop, Prop, setProp, getProp; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getProp() { return x; } + public void setProp(int v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class G11 { + + private final static String TESTCASE = + "getter + similarly named field of other type"; + + public Object prop, Prop, setProp, getProp; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getProp() { return X; } + public void setProp(int v) { prop = Prop = setProp = getProp = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class S11 { + + private final static String TESTCASE = + "setter + similarly named field of other type"; + + public String prop, Prop, setProp, getProp; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getProp() { return x; } + public void setProp(int v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132163 + public static class G12 { + + private final static String TESTCASE = + "getter having wrapper class return type"; + + private final int x = X; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public Integer getProp() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132163 + public static class S12 { + + private final static String TESTCASE = + "setter with wrapper class argument type"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(Integer v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class G13 { + + private final static String TESTCASE = + "getter + overloading methods"; + + private final int x = X; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getX() { return x; } + public int getX(boolean arg) { return (arg ? x : 0); } + public int getX(int ... dummy) { return 0; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8154756 + public static class S13 { + + private final static String TESTCASE = + "setter + overloading methods"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(int v) { x = v; } + public int setX() { return (x = X); } + public void setX(int ... dummy) {} + private void setX(Object ... dummy) {} + + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + + // JDK-8132888 + public static class G14 { + + private final static String TESTCASE = "non-public getter"; + + private final int x = X; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + int getX() { return x; } // getter is not public + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132888 + public static class S14 { + + private final static String TESTCASE = "non-public setter"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + void setX(int v) { x = v; } // setter is not public + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class getX { + + private final static String TESTCASE = + "class name coincides with getter name"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getX() { return x; } + public void setX(int v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class setX { + + private final static String TESTCASE = + "class name coincides with setter name"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(int v) { x = v; } + public int getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132973 + public static class GS { + + private final static String TESTCASE = + "both getter and setter are annotated"; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getX() { return x; } + + @BeanProperty( + description = DESCRIPTION_2, + bound = !BOUND, + expert = !EXPERT, + hidden = !HIDDEN, + preferred = !PREFERRED, + required = !REQUIRED, + visualUpdate = !UPDATE) + public void setX(int v) { x = v; } + + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + + + + // ---------- checks ---------- + + private static boolean check(String what, boolean v, boolean ref) { + + boolean ok = (v == ref); + if (!ok) { System.out.println( + "invalid " + what + ": " + v + ", expected: " + ref); } + return ok; + } + + private static boolean checkInfo(BeanInfo i) { + + System.out.println("checking info..."); + + PropertyDescriptor descriptors[] = i.getPropertyDescriptors(); + int nd = descriptors.length; + if (nd != 1) { + System.out.println("invalid number of descriptors: " + nd); + return false; + } + + PropertyDescriptor d = descriptors[0]; + + String descr = d.getShortDescription(); + boolean ok = descr.equals(DESCRIPTION); + if (!ok) { System.out.println("invalid description: " + descr + + ", expected: " + DESCRIPTION); } + + ok &= check("isBound", d.isBound(), BOUND); + ok &= check("isExpert", d.isExpert(), EXPERT); + ok &= check("isHidden", d.isHidden(), HIDDEN); + ok &= check("isPreferred", d.isPreferred(), PREFERRED); + ok &= check("required", (boolean) d.getValue("required"), REQUIRED); + ok &= check("visualUpdate", + (boolean) d.getValue("visualUpdate"), UPDATE); + + Object vals[] = (Object[]) d.getValue("enumerationValues"); + if (vals == null) { + System.out.println("null enumerationValues"); + return false; + } + + boolean okVals = ( + (vals.length == 3) && + vals[0].toString().equals(V_SHORT) && + vals[1].toString().equals(V) && + vals[2].toString().equals(V_NAME)); + + if (!okVals) { System.out.println("invalid enumerationValues"); } + + return (ok && okVals); + } + + private static boolean checkAlternativeInfo(BeanInfo i) { + + System.out.println("checking alternative info..."); + + PropertyDescriptor descriptors[] = i.getPropertyDescriptors(); + int nd = descriptors.length; + if (nd != 1) { + System.out.println("invalid number of descriptors: " + nd); + return false; + } + + PropertyDescriptor d = descriptors[0]; + + String descr = d.getShortDescription(); + boolean ok = descr.equals(DESCRIPTION_2); + if (!ok) { System.out.println("invalid alternative description: " + + descr + ", expected: " + DESCRIPTION_2); } + + ok &= check("isBound", d.isBound(), !BOUND); + ok &= check("isExpert", d.isExpert(), !EXPERT); + ok &= check("isHidden", d.isHidden(), !HIDDEN); + ok &= check("isPreferred", d.isPreferred(), !PREFERRED); + ok &= check("required", (boolean) d.getValue("required"), !REQUIRED); + ok &= check("visualUpdate", + (boolean) d.getValue("visualUpdate"), !UPDATE); + + Object vals[] = (Object[]) d.getValue("enumerationValues"); + if (vals != null || vals.length > 0) { + System.out.println("non-null enumerationValues"); + return false; + } + + return ok; + } + + + private static boolean checkAlternative(Class c) { + return ( + c.equals(G09.class) || + c.equals(S09.class) || + c.equals(GS.class)); + } + + + // ---------- run test ---------- + + public static void main(String[] args) throws Exception { + + Class cases[] = { + + G01.class, S01.class, + // G02.class, S02.class, // TODO: please update after 8132703 fix + // G03.class, S03.class, // TODO: please update after 8132703 fix + // G04.class, S04.class, // TODO: please update after 8132163 fix + G05.class, // S05.class, // TODO: please update after 8132163 fix + G06.class, S06.class, + G07.class, S07.class, + // G08.class, S08.class, // TODO: please update after 8132732 fix + // G09.class, S09.class, // TODO: please update after 8132732 fix + G10.class, S10.class, + G11.class, S11.class, + // G12.class, S12.class, // TODO: please update after 8132163 fix + G13.class, // S13.class, // TODO: please update after 8154756 fix + // G14.class, S14.class, // TODO: please update after 8132888 fix or + // remove these cases if it is not an issue + // GS.class, // TODO: please update after 8132973 fix + getX.class, setX.class + }; + + boolean passed = true; + + for (Class c: cases) { + + java.lang.reflect.Field f = c.getDeclaredField("TESTCASE"); + f.setAccessible(true); + String descr = f.get(c).toString(); + + System.out.println("\n" + c.getSimpleName() + " (" + descr + "):"); + BeanInfo i; + try { i = Introspector.getBeanInfo(c, Object.class); } + catch (IntrospectionException e) { throw new RuntimeException(e); } + boolean ok = checkInfo(i); + if (checkAlternative(c)) { + ok |= checkAlternativeInfo(i); + } + System.out.println(ok ? "OK" : "NOK"); + passed = passed && ok; + } + + if (!passed) { throw new RuntimeException("test failed"); } + System.out.println("\ntest passed"); + } +} From 1d0549f73ee2a3ea57234c3da05507b8ef22f4b5 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 21 Apr 2016 12:57:03 -0700 Subject: [PATCH 124/222] Added tag jdk-9+115 for changeset 4fbd14764fa7 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index e13ddc6f1e0..06edc4a1f53 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -357,3 +357,4 @@ f900d5afd9c83a0df8f36161c27c5e4c86a66f4c jdk-9+111 03543a758cd5890f2266e4b9678378a925dde22a jdk-9+112 55b6d550828d1223b364e6ead4a56e56411c56df jdk-9+113 1d992540870ff33fe6cc550443388588df9b9e4f jdk-9+114 +09617ce980b99d49abfd54dacfed353c47e2a115 jdk-9+115 From 9fe8b397dd0cbb96e395e8e5a65115ce4a0bf27d Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 21 Apr 2016 12:57:05 -0700 Subject: [PATCH 125/222] Added tag jdk-9+115 for changeset 5daa5fbad3ce --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index df49fd73654..dd25acb220b 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -357,3 +357,4 @@ b75afa17aefe480c23c616a6a2497063312f7189 jdk-9+109 780d0620add32bf545471cf65038c9ac6d9c036d jdk-9+112 cc30faa2da498c478e89ab062ff160653ca1b170 jdk-9+113 10d175b0368c30f54350fc648adc41b94ce357ee jdk-9+114 +7bab1b1b36824924b1c657a8419369ba93d198d3 jdk-9+115 From 2c681d330ed0750bf357c8ba6afae5accb279f4d Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 21 Apr 2016 12:57:09 -0700 Subject: [PATCH 126/222] Added tag jdk-9+115 for changeset 04a4a89d81b9 --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 99d74713f24..07b1b9985f7 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -357,3 +357,4 @@ bdbf2342b21bd8ecad1b4e6499a0dfb314952bd7 jdk-9+103 36326537f929d20cc5885b93939f90c0efcc4681 jdk-9+112 28626780e245fccbfb9bad8e3b05f62357958038 jdk-9+113 147114dd0641cd7c9fe6e81642eb993a7b9c6f0b jdk-9+114 +1902a5bda18e794b31fc5f520f5e7d827714b50d jdk-9+115 From 6e60b5bc3ef83efdc0143436c3131573ea922ca6 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 21 Apr 2016 12:57:10 -0700 Subject: [PATCH 127/222] Added tag jdk-9+115 for changeset c0f1d63d6486 --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index c0e2ef494a3..7781746dc33 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -360,3 +360,4 @@ fafd694e801f0f5a7c737fb08630ced3ca8f772c jdk-9+107 21274e7937bae291658d68143aca0e3ee9296db0 jdk-9+112 e980062475c10d21137051045bf95ee229db9b27 jdk-9+113 b314bb02182b9ca94708a91f312c377f5435f740 jdk-9+114 +4ff86e5489e4c0513dadfa69def8601c110ca5cd jdk-9+115 From ae0df303d1080640613cfb775148828aff5b03dc Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 21 Apr 2016 12:57:17 -0700 Subject: [PATCH 128/222] Added tag jdk-9+115 for changeset e9c85d2b1fcc --- nashorn/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/nashorn/.hgtags b/nashorn/.hgtags index 5d1fa7fb250..78e30d77611 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -348,3 +348,4 @@ cfb3167456932b14c16a6d4cffd5fe295fbe01ff jdk-9+106 c261f8440c5578b34596e6b0419a81aec431a884 jdk-9+112 a5d1990fd32d908da8154d79116fce8013ba4d40 jdk-9+113 ba21793a0e4816283cc0ecdab5142a4959363529 jdk-9+114 +295ac208a4443d433214d0c1f32d2ea45a3a32d2 jdk-9+115 From 6c7656678916ff3f5c9fc70efcbb69ce76801458 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 22 Apr 2016 01:59:35 +0300 Subject: [PATCH 129/222] 8154088: [macosx] SWT does not work on JDK 9 since b65 Reviewed-by: prr --- .../sun/lwawt/macosx/CViewEmbeddedFrame.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java index 095922047fe..5fbb825a342 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java @@ -87,23 +87,22 @@ public class CViewEmbeddedFrame extends EmbeddedFrame { } } - /* + /** * Initializes the embedded frame bounds and validates a component. - * Designed to be called from the main thread - * This method should be called once from the initialization of the SWT_AWT Bridge + * Designed to be called from the main thread. This method should be called + * once from the initialization of the SWT_AWT Bridge. */ - public void validateWithBounds(final int x, final int y, final int width, final int height) { + public void validateWithBounds(final int x, final int y, final int width, + final int height) { try { - final LWWindowPeer peer = AWTAccessor.getComponentAccessor() - .getPeer(this); - LWCToolkit.invokeAndWait(new Runnable() { - @Override - public void run() { - peer.setBoundsPrivate(0, 0, width, height); - validate(); - setVisible(true); - } + LWCToolkit.invokeAndWait(() -> { + final LWWindowPeer peer = AWTAccessor.getComponentAccessor() + .getPeer(this); + peer.setBoundsPrivate(0, 0, width, height); + validate(); + setVisible(true); }, this); - } catch (InvocationTargetException ex) {} + } catch (InvocationTargetException ex) { + } } } From 2ee49b78fe6ac31d4fb992adaad702333d85c2a9 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 22 Apr 2016 10:46:08 +0200 Subject: [PATCH 130/222] 8154867: PPC64: Better byte behavior Reviewed-by: goetz --- .../src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp | 5 +- hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp | 40 +++++++++++++ hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp | 2 + .../vm/templateInterpreterGenerator_ppc.cpp | 12 +++- .../src/cpu/ppc/vm/templateTable_ppc_64.cpp | 60 +++++++++++++++++-- 5 files changed, 111 insertions(+), 8 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp index cba04106f8c..0d1cb4711bd 100644 --- a/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp @@ -360,7 +360,7 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { length.set_instruction(x->length()); length.load_item(); } - if (needs_store_check) { + if (needs_store_check || x->check_boolean()) { value.load_item(); } else { value.load_for_store(x->elt_type()); @@ -407,7 +407,8 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, true /* do_load */, false /* patch */, NULL); } - __ move(value.result(), array_addr, null_check_info); + LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info); + __ move(result, array_addr, null_check_info); if (obj_store) { // Precise card mark. post_barrier(LIR_OprFact::address(array_addr), value.result()); diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp index 9c7128da0b4..cedc1e08c1c 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp @@ -169,6 +169,7 @@ void InterpreterMacroAssembler::load_earlyret_value(TosState state, Register Rsc case ltos: ld(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); break; case btos: // fall through + case ztos: // fall through case ctos: // fall through case stos: // fall through case itos: lwz(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); @@ -294,6 +295,7 @@ void InterpreterMacroAssembler::push(TosState state) { switch (state) { case atos: push_ptr(); break; case btos: + case ztos: case ctos: case stos: case itos: push_i(); break; @@ -309,6 +311,7 @@ void InterpreterMacroAssembler::pop(TosState state) { switch (state) { case atos: pop_ptr(); break; case btos: + case ztos: case ctos: case stos: case itos: pop_i(); break; @@ -749,6 +752,43 @@ void InterpreterMacroAssembler::merge_frames(Register Rsender_sp, Register retur stdux(Rscratch2, R1_SP, Rscratch1); // atomically set *(SP = top_frame_sp) = **SP } +void InterpreterMacroAssembler::narrow(Register result) { + Register ret_type = R11_scratch1; + ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method); + lbz(ret_type, in_bytes(ConstMethod::result_type_offset()), R11_scratch1); + + Label notBool, notByte, notChar, done; + + // common case first + cmpwi(CCR0, ret_type, T_INT); + beq(CCR0, done); + + cmpwi(CCR0, ret_type, T_BOOLEAN); + bne(CCR0, notBool); + andi(result, result, 0x1); + b(done); + + bind(notBool); + cmpwi(CCR0, ret_type, T_BYTE); + bne(CCR0, notByte); + extsb(result, result); + b(done); + + bind(notByte); + cmpwi(CCR0, ret_type, T_CHAR); + bne(CCR0, notChar); + andi(result, result, 0xffff); + b(done); + + bind(notChar); + // cmpwi(CCR0, ret_type, T_SHORT); // all that's left + // bne(CCR0, done); + extsh(result, result); + + // Nothing to do for T_INT + bind(done); +} + // Remove activation. // // Unlock the receiver if this is a synchronized method. diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp index 8a75af011bd..05bd3aa0bdd 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp @@ -140,6 +140,8 @@ class InterpreterMacroAssembler: public MacroAssembler { void get_cpool_and_tags(Register Rcpool, Register Rtags); void is_a(Label& L); + void narrow(Register result); + // Java Call Helpers void call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2); diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp index 8979e213acf..3602c646192 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp @@ -655,6 +655,7 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, switch (state) { case ltos: case btos: + case ztos: case ctos: case stos: case atos: @@ -701,6 +702,7 @@ address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, i switch (state) { case ltos: case btos: + case ztos: case ctos: case stos: case atos: @@ -2092,12 +2094,14 @@ address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state // Copied from TemplateTable::_return. // Restoration of lr done by remove_activation. switch (state) { + // Narrow result if state is itos but result type is smaller. + case itos: __ narrow(R17_tos); /* fall through */ case ltos: case btos: + case ztos: case ctos: case stos: - case atos: - case itos: __ mr(R3_RET, R17_tos); break; + case atos: __ mr(R3_RET, R17_tos); break; case ftos: case dtos: __ fmr(F1_RET, F15_ftos); break; case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need @@ -2157,6 +2161,10 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) { bname = "trace_code_btos {"; tsize = 2; break; + case ztos: + bname = "trace_code_ztos {"; + tsize = 2; + break; case ctos: bname = "trace_code_ctos {"; tsize = 2; diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp index c59e7b4b38b..6b8f658ff09 100644 --- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp @@ -170,6 +170,7 @@ void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Reg switch (new_bc) { case Bytecodes::_fast_aputfield: case Bytecodes::_fast_bputfield: + case Bytecodes::_fast_zputfield: case Bytecodes::_fast_cputfield: case Bytecodes::_fast_dputfield: case Bytecodes::_fast_fputfield: @@ -981,9 +982,21 @@ void TemplateTable::bastore() { Rarray = R12_scratch2, Rscratch = R3_ARG1; __ pop_i(Rindex); + __ pop_ptr(Rarray); // tos: val - // Rarray: array ptr (popped by index_check) - __ index_check(Rarray, Rindex, 0, Rscratch, Rarray); + + // Need to check whether array is boolean or byte + // since both types share the bastore bytecode. + __ load_klass(Rscratch, Rarray); + __ lwz(Rscratch, in_bytes(Klass::layout_helper_offset()), Rscratch); + int diffbit = exact_log2(Klass::layout_helper_boolean_diffbit()); + __ testbitdi(CCR0, R0, Rscratch, diffbit); + Label L_skip; + __ bfalse(CCR0, L_skip); + __ andi(R17_tos, R17_tos, 1); // if it is a T_BOOLEAN array, mask the stored value to 0/1 + __ bind(L_skip); + + __ index_check_without_pop(Rarray, Rindex, 0, Rscratch, Rarray); __ stb(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rarray); } @@ -2108,12 +2121,16 @@ void TemplateTable::_return(TosState state) { __ remove_activation(state, /* throw_monitor_exception */ true); // Restoration of lr done by remove_activation. switch (state) { + // Narrow result if state is itos but result type is smaller. + // Need to narrow in the return bytecode rather than in generate_return_entry + // since compiled code callers expect the result to already be narrowed. + case itos: __ narrow(R17_tos); /* fall through */ case ltos: case btos: + case ztos: case ctos: case stos: - case atos: - case itos: __ mr(R3_RET, R17_tos); break; + case atos: __ mr(R3_RET, R17_tos); break; case ftos: case dtos: __ fmr(F1_RET, F15_ftos); break; case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need @@ -2518,6 +2535,21 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ beq(CCR6, Lacquire); // Volatile? __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + __ align(32, 28, 28); // Align load. + // __ bind(Lztos); (same code as btos) + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ztos] == 0, "can't compute twice"); + branch_table[ztos] = __ pc(); // non-volatile_entry point + __ lbzx(R17_tos, Rclass_or_obj, Roffset); + __ extsb(R17_tos, R17_tos); + __ push(ztos); + if (!is_static) { + // use btos rewriting, no truncating to t/f bit is needed for getfield. + patch_bytecode(Bytecodes::_fast_bgetfield, Rbc, Rscratch); + } + __ beq(CCR6, Lacquire); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + __ align(32, 28, 28); // Align load. // __ bind(Lctos); __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). @@ -2618,6 +2650,7 @@ void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, boo case Bytecodes::_fast_aputfield: __ push_ptr(); offs+= Interpreter::stackElementSize; break; case Bytecodes::_fast_iputfield: // Fall through case Bytecodes::_fast_bputfield: // Fall through + case Bytecodes::_fast_zputfield: // Fall through case Bytecodes::_fast_cputfield: // Fall through case Bytecodes::_fast_sputfield: __ push_i(); offs+= Interpreter::stackElementSize; break; case Bytecodes::_fast_lputfield: __ push_l(); offs+=2*Interpreter::stackElementSize; break; @@ -2658,6 +2691,7 @@ void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, boo case Bytecodes::_fast_aputfield: __ pop_ptr(); break; case Bytecodes::_fast_iputfield: // Fall through case Bytecodes::_fast_bputfield: // Fall through + case Bytecodes::_fast_zputfield: // Fall through case Bytecodes::_fast_cputfield: // Fall through case Bytecodes::_fast_sputfield: __ pop_i(); break; case Bytecodes::_fast_lputfield: __ pop_l(); break; @@ -2824,6 +2858,21 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + __ align(32, 28, 28); // Align pop. + // __ bind(Lztos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ztos] == 0, "can't compute twice"); + branch_table[ztos] = __ pc(); // non-volatile_entry point + __ pop(ztos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ andi(R17_tos, R17_tos, 0x1); + __ stbx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_zputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + } + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + __ align(32, 28, 28); // Align pop. // __ bind(Lctos); __ release(); // Volatile entry point (one instruction before non-volatile_entry point). @@ -2949,6 +2998,9 @@ void TemplateTable::fast_storefield(TosState state) { __ stdx(R17_tos, Rclass_or_obj, Roffset); break; + case Bytecodes::_fast_zputfield: + __ andi(R17_tos, R17_tos, 0x1); // boolean is true if LSB is 1 + // fall through to bputfield case Bytecodes::_fast_bputfield: __ stbx(R17_tos, Rclass_or_obj, Roffset); break; From f2c59f97ce65dd3c7eb879bfaa085e2ec8799e76 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 22 Apr 2016 10:48:12 +0200 Subject: [PATCH 131/222] 8154326: bash >(...) construct causes race conditions Reviewed-by: tbell, ihse --- make/InitSupport.gmk | 2 +- make/common/MakeBase.gmk | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk index 493591ebbec..cee30522d33 100644 --- a/make/InitSupport.gmk +++ b/make/InitSupport.gmk @@ -331,7 +331,7 @@ else # $(HAS_SPEC)=true BUILD_LOG := $(OUTPUT_ROOT)/build.log BUILD_TRACE_LOG := $(OUTPUT_ROOT)/build-trace-time.log - BUILD_LOG_PIPE := > >($(TEE) -a $(BUILD_LOG)) 2> >($(TEE) -a $(BUILD_LOG) >&2) + BUILD_LOG_PIPE := > >($(TEE) -a $(BUILD_LOG)) 2> >($(TEE) -a $(BUILD_LOG) >&2) && wait # Sanity check the spec file, so it matches this source code define CheckSpecSanity diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index 6f1f00b99d5..f159b8fca63 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -706,10 +706,10 @@ endif ExecuteWithLog = \ $(call LogCmdlines, Exececuting: [$(strip $2)]) \ $(call WriteFile, $2, $(strip $1).cmdline) \ - ( $(strip $2) > >($(TEE) $(strip $1).log) 2> >($(TEE) $(strip $1).log >&2) || \ + ( ( $(strip $2) > >($(TEE) $(strip $1).log) 2> >($(TEE) $(strip $1).log >&2) || \ ( exitcode=$(DOLLAR)? && \ $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(BUILD_OUTPUT)/%,%,$(strip $1))).log && \ - exit $(DOLLAR)exitcode ) ) + exit $(DOLLAR)exitcode ) ) && wait ) ################################################################################ # Find lib dir for module From 911f4b1664c6b7f6d2c2208c8f3ae052ea170aa7 Mon Sep 17 00:00:00 2001 From: Nadeesh TV Date: Mon, 25 Apr 2016 09:37:43 +0000 Subject: [PATCH 132/222] 8031085: DateTimeFormatter won't parse dates with custom format "yyyyMMddHHmmssSSS" Changed the FractionPrinterParser to subclass of NumberPrinterParser to make it participate in adjacent value parsing Reviewed-by: rriggs, scolebourne --- .../time/format/DateTimeFormatterBuilder.java | 81 ++++++++++++++++--- .../format/TCKDateTimeFormatterBuilder.java | 18 ++++- 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index e8ca3f1e99f..a36d1b5e142 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -667,8 +667,11 @@ public final class DateTimeFormatterBuilder { * No rounding occurs due to the maximum width - digits are simply dropped. *

    * When parsing in strict mode, the number of parsed digits must be between - * the minimum and maximum width. When parsing in lenient mode, the minimum - * width is considered to be zero and the maximum is nine. + * the minimum and maximum width. In strict mode, if the minimum and maximum widths + * are equal and there is no decimal point then the parser will + * participate in adjacent value parsing, see + * {@link appendValue(java.time.temporal.TemporalField, int)}. When parsing in lenient mode, + * the minimum width is considered to be zero and the maximum is nine. *

    * If the value cannot be obtained then an exception will be thrown. * If the value is negative an exception will be thrown. @@ -687,7 +690,12 @@ public final class DateTimeFormatterBuilder { */ public DateTimeFormatterBuilder appendFraction( TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) { - appendInternal(new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint)); + if (minWidth == maxWidth && decimalPoint == false) { + // adjacent parsing + appendValue(new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint)); + } else { + appendInternal(new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint)); + } return this; } @@ -2925,11 +2933,8 @@ public final class DateTimeFormatterBuilder { /** * Prints and parses a numeric date-time field with optional padding. */ - static final class FractionPrinterParser implements DateTimePrinterParser { - private final TemporalField field; - private final int minWidth; - private final int maxWidth; - private final boolean decimalPoint; + static final class FractionPrinterParser extends NumberPrinterParser { + private final boolean decimalPoint; /** * Constructor. @@ -2940,6 +2945,7 @@ public final class DateTimeFormatterBuilder { * @param decimalPoint whether to output the localized decimal point symbol */ FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) { + this(field, minWidth, maxWidth, decimalPoint, 0); Objects.requireNonNull(field, "field"); if (field.range().isFixed() == false) { throw new IllegalArgumentException("Field must have a fixed set of values: " + field); @@ -2954,12 +2960,61 @@ public final class DateTimeFormatterBuilder { throw new IllegalArgumentException("Maximum width must exceed or equal the minimum width but " + maxWidth + " < " + minWidth); } - this.field = field; - this.minWidth = minWidth; - this.maxWidth = maxWidth; + } + + /** + * Constructor. + * + * @param field the field to output, not null + * @param minWidth the minimum width to output, from 0 to 9 + * @param maxWidth the maximum width to output, from 0 to 9 + * @param decimalPoint whether to output the localized decimal point symbol + * @param subsequentWidth the subsequentWidth for this instance + */ + FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) { + super(field, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth); this.decimalPoint = decimalPoint; } + /** + * Returns a new instance with fixed width flag set. + * + * @return a new updated printer-parser, not null + */ + @Override + FractionPrinterParser withFixedWidth() { + if (subsequentWidth == -1) { + return this; + } + return new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint, -1); + } + + /** + * Returns a new instance with an updated subsequent width. + * + * @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater + * @return a new updated printer-parser, not null + */ + @Override + FractionPrinterParser withSubsequentWidth(int subsequentWidth) { + return new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint, this.subsequentWidth + subsequentWidth); + } + + /** + * For FractionPrinterPrinterParser, the width is fixed if context is sttrict, + * minWidth equal to maxWidth and decimalpoint is absent. + * @param context the context + * @return if the field is fixed width + * @see DateTimeFormatterBuilder#appendValueFraction(java.time.temporal.TemporalField, int, int, boolean) + */ + @Override + boolean isFixedWidth(DateTimeParseContext context) { + if (context.isStrict() && minWidth == maxWidth && decimalPoint == false) { + return true; + } + return false; + } + @Override public boolean format(DateTimePrintContext context, StringBuilder buf) { Long value = context.getValue(field); @@ -2992,8 +3047,8 @@ public final class DateTimeFormatterBuilder { @Override public int parse(DateTimeParseContext context, CharSequence text, int position) { - int effectiveMin = (context.isStrict() ? minWidth : 0); - int effectiveMax = (context.isStrict() ? maxWidth : 9); + int effectiveMin = (context.isStrict() || isFixedWidth(context) ? minWidth : 0); + int effectiveMax = (context.isStrict() || isFixedWidth(context) ? maxWidth : 9); int length = text.length(); if (position == length) { // valid if whole field is optional, invalid if minimum width diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java index 2fde35b5e2c..14d7e0359d4 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java @@ -71,6 +71,7 @@ import static org.testng.Assert.assertEquals; import java.text.ParsePosition; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.YearMonth; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; @@ -930,7 +931,7 @@ public class TCKDateTimeFormatterBuilder { @Test public void test_adjacent_lenient_fractionFollows_0digit() throws Exception { - // succeeds because hour/min are fixed width + // succeeds because hour, min and fraction of seconds are fixed width DateTimeFormatter f = builder.parseLenient().appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendFraction(NANO_OF_SECOND, 3, 3, false).toFormatter(Locale.UK); ParsePosition pp = new ParsePosition(0); TemporalAccessor parsed = f.parseUnresolved("1230", pp); @@ -940,6 +941,21 @@ public class TCKDateTimeFormatterBuilder { assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); } + @DataProvider(name="adjacentFractionParseData") + Object[][] data_adjacent_fraction_parse() { + return new Object[][] { + {"20130812214600025", "yyyyMMddHHmmssSSS", LocalDateTime.of(2013, 8, 12, 21, 46, 00, 25000000)}, + {"201308122146000256", "yyyyMMddHHmmssSSSS", LocalDateTime.of(2013, 8, 12, 21, 46, 00, 25600000)}, + }; + } + + @Test(dataProvider = "adjacentFractionParseData") + public void test_adjacent_fraction(String input, String pattern, LocalDateTime expected) { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern(pattern); + LocalDateTime actual = LocalDateTime.parse(input, dtf); + assertEquals(actual, expected); + } + @DataProvider(name="lenientOffsetParseData") Object[][] data_lenient_offset_parse() { return new Object[][] { From 080a341e800547fdcd7f6749ec3e0169c3da9efc Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Mon, 25 Apr 2016 15:37:31 +0300 Subject: [PATCH 133/222] 8145547: [AWT/Swing] Conditional support for GTK 3 on Linux Reviewed-by: prr, alexsch --- jdk/make/mapfiles/libawt_xawt/mapfile-vers | 1 + .../sun/java/swing/plaf/gtk/GTKEngine.java | 20 +- .../java/swing/plaf/gtk/GTKLookAndFeel.java | 33 +- .../sun/java/swing/plaf/gtk/GTKPainter.java | 55 +- .../com/sun/java/swing/plaf/gtk/GTKStyle.java | 21 +- .../unix/classes/sun/awt/UNIXToolkit.java | 71 +- .../classes/sun/awt/X11/XDesktopPeer.java | 9 +- .../classes/sun/awt/X11/XTaskbarPeer.java | 9 +- .../unix/classes/sun/awt/X11/XToolkit.java | 3 +- .../unix/native/libawt_xawt/awt/awt_Robot.c | 72 +- .../native/libawt_xawt/awt/awt_UNIXToolkit.c | 92 +- .../native/libawt_xawt/awt/gtk2_interface.c | 405 ++- .../native/libawt_xawt/awt/gtk2_interface.h | 512 +-- .../native/libawt_xawt/awt/gtk3_interface.c | 2881 +++++++++++++++++ .../native/libawt_xawt/awt/gtk3_interface.h | 577 ++++ .../native/libawt_xawt/awt/gtk_interface.c | 158 + .../native/libawt_xawt/awt/gtk_interface.h | 560 ++++ .../awt/sun_awt_X11_GtkFileDialogPeer.c | 80 +- .../native/libawt_xawt/awt/swing_GTKEngine.c | 141 +- .../native/libawt_xawt/awt/swing_GTKStyle.c | 37 +- .../native/libawt_xawt/xawt/awt_Desktop.c | 14 +- .../native/libawt_xawt/xawt/awt_Taskbar.c | 35 +- .../native/libawt_xawt/xawt/awt_Taskbar.h | 2 +- .../native/libawt_xawt/xawt/gnome_interface.h | 4 +- 24 files changed, 4862 insertions(+), 930 deletions(-) create mode 100644 jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c create mode 100644 jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h create mode 100644 jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.c create mode 100644 jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h diff --git a/jdk/make/mapfiles/libawt_xawt/mapfile-vers b/jdk/make/mapfiles/libawt_xawt/mapfile-vers index 2b18bd42e6f..b56fad43b4f 100644 --- a/jdk/make/mapfiles/libawt_xawt/mapfile-vers +++ b/jdk/make/mapfiles/libawt_xawt/mapfile-vers @@ -179,6 +179,7 @@ SUNWprivate_1.1 { Java_sun_awt_UNIXToolkit_load_1gtk_1icon; Java_sun_awt_UNIXToolkit_nativeSync; Java_sun_awt_UNIXToolkit_gtkCheckVersionImpl; + Java_sun_awt_UNIXToolkit_get_1gtk_1version; Java_java_awt_AWTEvent_initIDs; Java_java_awt_event_InputEvent_initIDs; Java_java_awt_event_KeyEvent_initIDs; diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java index f52982a4461..940b0107a93 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -158,8 +158,8 @@ class GTKEngine { int widgetType, int state, int shadowType, String detail, int x, int y, int width, int height, int synthState, int dir); private native void native_paint_slider( - int widgetType, int state, int shadowType, String detail, - int x, int y, int width, int height, int orientation); + int widgetType, int state, int shadowType, String detail, int x, + int y, int width, int height, int orientation, boolean hasFocus); private native void native_paint_vline( int widgetType, int state, String detail, int x, int y, int width, int height); @@ -491,6 +491,14 @@ class GTKEngine { int gtkState = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal(); int synthState = context.getComponentState(); + Container parent = context.getComponent().getParent(); + if(GTKLookAndFeel.is3()) { + if (parent != null && parent.getParent() instanceof JComboBox) { + if (parent.getParent().hasFocus()) { + synthState |= SynthConstants.FOCUSED; + } + } + } int dir = getTextDirection(context); int widget = getWidgetType(context.getComponent(), id).ordinal(); native_paint_shadow(widget, gtkState, shadowType.ordinal(), detail, @@ -498,13 +506,13 @@ class GTKEngine { } public void paintSlider(Graphics g, SynthContext context, - Region id, int state, ShadowType shadowType, String detail, - int x, int y, int w, int h, Orientation orientation) { + Region id, int state, ShadowType shadowType, String detail, int x, + int y, int w, int h, Orientation orientation, boolean hasFocus) { state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal(); int widget = getWidgetType(context.getComponent(), id).ordinal(); native_paint_slider(widget, state, shadowType.ordinal(), detail, - x - x0, y - y0, w, h, orientation.ordinal()); + x - x0, y - y0, w, h, orientation.ordinal(), hasFocus); } public void paintVline(Graphics g, SynthContext context, diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index 199806d133a..f568f6a4bae 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,8 @@ import sun.swing.SwingUtilities2; */ @SuppressWarnings("serial") // Superclass not serializable public class GTKLookAndFeel extends SynthLookAndFeel { - private static final boolean IS_22; + private static boolean IS_22; + private static boolean IS_3; /** * Whether or not text is drawn antialiased. This keys off the @@ -107,17 +108,6 @@ public class GTKLookAndFeel extends SynthLookAndFeel { private static String gtkThemeName = "Default"; static { - // Backup for specifying the version, this isn't currently documented. - // If you pass in anything but 2.2 you got the 2.0 colors/look. - String version = AccessController.doPrivileged( - new GetPropertyAction("swing.gtk.version")); - if (version != null) { - IS_22 = version.equals("2.2"); - } - else { - IS_22 = true; - } - String language = Locale.getDefault().getLanguage(); boolean cjkLocale = (Locale.CHINESE.getLanguage().equals(language) || @@ -158,6 +148,10 @@ public class GTKLookAndFeel extends SynthLookAndFeel { return IS_22; } + static boolean is3() { + return IS_3; + } + /** * Maps a swing constant to a GTK constant. */ @@ -1460,6 +1454,19 @@ public class GTKLookAndFeel extends SynthLookAndFeel { throw new InternalError("Unable to load native GTK libraries"); } + if (UNIXToolkit.getGtkVersion() == UNIXToolkit.GtkVersions.GTK2) { + String version = AccessController.doPrivileged( + new GetPropertyAction("jdk.gtk.version")); + if (version != null) { + IS_22 = version.equals("2.2"); + } else { + IS_22 = true; + } + } else if (UNIXToolkit.getGtkVersion() == + UNIXToolkit.GtkVersions.GTK3) { + IS_3 = true; + } + super.initialize(); inInitialize = true; loadStyles(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java index ecd319a337f..a607d4c41d4 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java @@ -768,6 +768,15 @@ class GTKPainter extends SynthPainter { // The ubuntulooks engine paints slider troughs differently depending // on the current slider value and its component orientation. JSlider slider = (JSlider)context.getComponent(); + if (GTKLookAndFeel.is3()) { + if (slider.getOrientation() == JSlider.VERTICAL) { + y += 1; + h -= 2; + } else { + x += 1; + w -= 2; + } + } double value = slider.getValue(); double min = slider.getMinimum(); double max = slider.getMaximum(); @@ -801,15 +810,19 @@ class GTKPainter extends SynthPainter { Region id = context.getRegion(); int gtkState = GTKLookAndFeel.synthStateToGTKState( id, context.getComponentState()); + boolean hasFocus = GTKLookAndFeel.is3() && + ((context.getComponentState() & SynthConstants.FOCUSED) != 0); synchronized (UNIXToolkit.GTK_LOCK) { - if (! ENGINE.paintCachedImage(g, x, y, w, h, id, gtkState, dir)) { + if (! ENGINE.paintCachedImage(g, x, y, w, h, id, gtkState, dir, + hasFocus)) { Orientation orientation = (dir == JSlider.HORIZONTAL ? Orientation.HORIZONTAL : Orientation.VERTICAL); String detail = (dir == JSlider.HORIZONTAL ? "hscale" : "vscale"); ENGINE.startPainting(g, x, y, w, h, id, gtkState, dir); ENGINE.paintSlider(g, context, id, gtkState, - ShadowType.OUT, detail, x, y, w, h, orientation); + ShadowType.OUT, detail, x, y, w, h, orientation, + hasFocus); ENGINE.finishPainting(); } } @@ -988,15 +1001,21 @@ class GTKPainter extends SynthPainter { int yThickness = style.getYThickness(); ENGINE.startPainting(g, x, y, w, h, id, state); + if (GTKLookAndFeel.is3()) { + ENGINE.paintBackground(g, context, id, gtkState, null, + x, y, w, h); + } ENGINE.paintShadow(g, context, id, gtkState, ShadowType.IN, "entry", x, y, w, h); - ENGINE.paintFlatBox(g, context, id, - gtkState, ShadowType.NONE, "entry_bg", - x + xThickness, - y + yThickness, - w - (2 * xThickness), - h - (2 * yThickness), - ColorType.TEXT_BACKGROUND); + if (!GTKLookAndFeel.is3()) { + ENGINE.paintFlatBox(g, context, id, + gtkState, ShadowType.NONE, "entry_bg", + x + xThickness, + y + yThickness, + w - (2 * xThickness), + h - (2 * yThickness), + ColorType.TEXT_BACKGROUND); + } if (focusSize > 0 && (state & SynthConstants.FOCUSED) != 0) { if (!interiorFocus) { @@ -1007,14 +1026,14 @@ class GTKPainter extends SynthPainter { } else { if (containerParent instanceof JComboBox) { x += (focusSize + 2); - y += (focusSize + 1); - w -= (2 * focusSize + 1); - h -= (2 * focusSize + 2); + y += focusSize + (GTKLookAndFeel.is3() ? 3 : 1); + w -= 2 * focusSize + (GTKLookAndFeel.is3() ? 4 : 1); + h -= 2 * focusSize + (GTKLookAndFeel.is3() ? 6 : 2); } else { - x += focusSize; - y += focusSize; - w -= 2 * focusSize; - h -= 2 * focusSize; + x += focusSize + (GTKLookAndFeel.is3() ? 2 : 0); + y += focusSize + (GTKLookAndFeel.is3() ? 2 :0 ); + w -= 2 * focusSize + (GTKLookAndFeel.is3() ? 4 : 0); + h -= 2 * focusSize + (GTKLookAndFeel.is3() ? 4 : 0); } } ENGINE.paintFocus(g, context, id, gtkState, @@ -1163,8 +1182,8 @@ class GTKPainter extends SynthPainter { Orientation orientation = (dir == JScrollBar.HORIZONTAL ? Orientation.HORIZONTAL : Orientation.VERTICAL); ENGINE.setRangeValue(context, id, value, min, max, visible); - ENGINE.paintSlider(g, context, id, gtkState, - ShadowType.OUT, "slider", x, y, w, h, orientation); + ENGINE.paintSlider(g, context, id, gtkState, ShadowType.OUT, + "slider", x, y, w, h, orientation, false); ENGINE.finishPainting(); } } diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java index fe54752cef6..2c60551dd04 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -715,29 +715,33 @@ class GTKStyle extends SynthStyle implements GTKConstants { if (region == Region.COMBO_BOX || region == Region.DESKTOP_PANE || region == Region.DESKTOP_ICON || - region == Region.EDITOR_PANE || - region == Region.FORMATTED_TEXT_FIELD || region == Region.INTERNAL_FRAME || region == Region.LIST || region == Region.MENU_BAR || region == Region.PANEL || - region == Region.PASSWORD_FIELD || region == Region.POPUP_MENU || region == Region.PROGRESS_BAR || region == Region.ROOT_PANE || region == Region.SCROLL_PANE || - region == Region.SPINNER || region == Region.SPLIT_PANE_DIVIDER || region == Region.TABLE || region == Region.TEXT_AREA || - region == Region.TEXT_FIELD || - region == Region.TEXT_PANE || region == Region.TOOL_BAR_DRAG_WINDOW || region == Region.TOOL_TIP || region == Region.TREE || region == Region.VIEWPORT) { return true; } + if (!GTKLookAndFeel.is3()) { + if (region == Region.EDITOR_PANE || + region == Region.FORMATTED_TEXT_FIELD || + region == Region.PASSWORD_FIELD || + region == Region.SPINNER || + region == Region.TEXT_FIELD || + region == Region.TEXT_PANE) { + return true; + } + } Component c = context.getComponent(); String name = c.getName(); if (name == "ComboBox.renderer" || name == "ComboBox.listRenderer") { @@ -848,6 +852,8 @@ class GTKStyle extends SynthStyle implements GTKConstants { int focusPad = getClassSpecificIntValue(context, "focus-padding", 1); return indicatorSpacing + focusSize + focusPad; + } else if (GTKLookAndFeel.is3() && "ComboBox.forceOpaque".equals(key)) { + return true; } // Is it a stock icon ? @@ -1127,6 +1133,7 @@ class GTKStyle extends SynthStyle implements GTKConstants { static { CLASS_SPECIFIC_MAP = new HashMap(); CLASS_SPECIFIC_MAP.put("Slider.thumbHeight", "slider-width"); + CLASS_SPECIFIC_MAP.put("Slider.thumbWidth", "slider-length"); CLASS_SPECIFIC_MAP.put("Slider.trackBorder", "trough-border"); CLASS_SPECIFIC_MAP.put("SplitPane.size", "handle-size"); CLASS_SPECIFIC_MAP.put("Tree.expanderSize", "expander-size"); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java b/jdk/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java index ecee8ade0bc..4e60992f314 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. * 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,9 +29,12 @@ import static java.awt.RenderingHints.*; import java.awt.color.ColorSpace; import java.awt.image.*; import java.security.AccessController; +import java.security.PrivilegedAction; + import sun.security.action.GetIntegerAction; import com.sun.java.swing.plaf.gtk.GTKConstants.TextDirection; import sun.java2d.opengl.OGLRenderQueue; +import sun.security.action.GetPropertyAction; public abstract class UNIXToolkit extends SunToolkit { @@ -42,6 +45,40 @@ public abstract class UNIXToolkit extends SunToolkit private static final int[] BAND_OFFSETS_ALPHA = { 0, 1, 2, 3 }; private static final int DEFAULT_DATATRANSFER_TIMEOUT = 10000; + // Allowed GTK versions + public enum GtkVersions { + ANY(0), + GTK2(Constants.GTK2_MAJOR_NUMBER), + GTK3(Constants.GTK3_MAJOR_NUMBER); + + static class Constants { + static final int GTK2_MAJOR_NUMBER = 2; + static final int GTK3_MAJOR_NUMBER = 3; + } + + final int number; + + GtkVersions(int number) { + this.number = number; + } + + public static GtkVersions getVersion(int number) { + switch (number) { + case Constants.GTK2_MAJOR_NUMBER: + return GTK2; + case Constants.GTK3_MAJOR_NUMBER: + return GTK3; + default: + return ANY; + } + } + + // major GTK version number + public int getNumber() { + return number; + } + }; + private Boolean nativeGTKAvailable; private Boolean nativeGTKLoaded; private BufferedImage tmpImage = null; @@ -79,7 +116,7 @@ public abstract class UNIXToolkit extends SunToolkit return nativeGTKAvailable; } else { - boolean success = check_gtk(); + boolean success = check_gtk(getEnabledGtkVersion().getNumber()); nativeGTKAvailable = success; return success; } @@ -97,7 +134,8 @@ public abstract class UNIXToolkit extends SunToolkit public boolean loadGTK() { synchronized (GTK_LOCK) { if (nativeGTKLoaded == null) { - nativeGTKLoaded = load_gtk(); + nativeGTKLoaded = load_gtk(getEnabledGtkVersion().getNumber(), + isGtkVerbose()); } } return nativeGTKLoaded; @@ -241,14 +279,15 @@ public abstract class UNIXToolkit extends SunToolkit tmpImage = new BufferedImage(colorModel, raster, false, null); } - private static native boolean check_gtk(); - private static native boolean load_gtk(); + private static native boolean check_gtk(int version); + private static native boolean load_gtk(int version, boolean verbose); private static native boolean unload_gtk(); private native boolean load_gtk_icon(String filename); private native boolean load_stock_icon(int widget_type, String stock_id, int iconSize, int textDirection, String detail); private native void nativeSync(); + private static native int get_gtk_version(); @Override public void sync() { @@ -338,4 +377,26 @@ public abstract class UNIXToolkit extends SunToolkit } return false; } + + public static GtkVersions getEnabledGtkVersion() { + String version = AccessController.doPrivileged( + new GetPropertyAction("jdk.gtk.version")); + if (version == null) { + return GtkVersions.ANY; + } else if (version.startsWith("2")) { + return GtkVersions.GTK2; + } else if("3".equals(version) ){ + return GtkVersions.GTK3; + } + return GtkVersions.ANY; + } + + public static GtkVersions getGtkVersion() { + return GtkVersions.getVersion(get_gtk_version()); + } + + public static boolean isGtkVerbose() { + return AccessController.doPrivileged((PrivilegedAction)() + -> Boolean.getBoolean("jdk.gtk.verbose")); + } } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDesktopPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDesktopPeer.java index 72a34cf85f8..b3d1c559442 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDesktopPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDesktopPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,8 @@ package sun.awt.X11; +import sun.awt.UNIXToolkit; + import java.io.File; import java.io.IOException; import java.net.MalformedURLException; @@ -57,7 +59,8 @@ public class XDesktopPeer implements DesktopPeer { XToolkit.awtLock(); try { if (!initExecuted) { - nativeLibraryLoaded = init(); + nativeLibraryLoaded = init(UNIXToolkit.getEnabledGtkVersion() + .ordinal(), UNIXToolkit.isGtkVerbose()); } } finally { initExecuted = true; @@ -123,5 +126,5 @@ public class XDesktopPeer implements DesktopPeer { } private native boolean gnome_url_show(byte[] url); - private static native boolean init(); + private static native boolean init(int gtkVersion, boolean verbose); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java index fa23ae0b66e..58b9559652a 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java @@ -29,6 +29,8 @@ import java.awt.PopupMenu; import java.awt.Taskbar.Feature; import java.awt.peer.TaskbarPeer; import java.awt.event.ActionEvent; + +import sun.awt.UNIXToolkit; import java.security.AccessController; import sun.security.action.GetPropertyAction; @@ -45,7 +47,9 @@ final class XTaskbarPeer implements TaskbarPeer { if (!initExecuted) { String dname = AccessController.doPrivileged( new GetPropertyAction("java.desktop.appName", "")); - nativeLibraryLoaded = init(dname); + nativeLibraryLoaded = init(dname, + UNIXToolkit.getEnabledGtkVersion().ordinal(), + UNIXToolkit.isGtkVerbose()); if (nativeLibraryLoaded) { Thread t = new Thread(null, () -> { runloop(); }, "TaskBar", 0, false); @@ -147,7 +151,8 @@ final class XTaskbarPeer implements TaskbarPeer { } } - private static native boolean init(String name); + private static native boolean init(String name, int version, + boolean verbose); private static native void runloop(); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index aa460f9f636..770244c964a 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -1144,7 +1144,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable { public FileDialogPeer createFileDialog(FileDialog target) { FileDialogPeer peer = null; // The current GtkFileChooser is available from GTK+ 2.4 - if (!getSunAwtDisableGtkFileDialogs() && checkGtkVersion(2, 4, 0)) { + if (!getSunAwtDisableGtkFileDialogs() && + (checkGtkVersion(2, 4, 0) || checkGtkVersion(3, 0, 0))) { peer = new GtkFileDialogPeer(target); } else { peer = new XFileDialogPeer(target); diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c index b066844ca74..91ad2515a8a 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "wsutils.h" #include "list.h" #include "multiVis.h" -#include "gtk2_interface.h" +#include "gtk_interface.h" #if defined(__linux__) || defined(MACOSX) #include @@ -263,70 +263,10 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, int index; if (isGtkSupported) { - GdkPixbuf *pixbuf; - (*fp_gdk_threads_enter)(); - GdkWindow *root = (*fp_gdk_get_default_root_window)(); - - pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(NULL, root, NULL, - x, y, 0, 0, width, height); - if (pixbuf && scale != 1) { - GdkPixbuf *scaledPixbuf; - x /= scale; - y /= scale; - width /= scale; - height /= scale; - dx /= scale; - dy /= scale; - scaledPixbuf = (*fp_gdk_pixbuf_scale_simple)(pixbuf, width, height, - GDK_INTERP_BILINEAR); - (*fp_g_object_unref)(pixbuf); - pixbuf = scaledPixbuf; - } - - if (pixbuf) { - int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); - int stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); - - if ((*fp_gdk_pixbuf_get_width)(pixbuf) == width - && (*fp_gdk_pixbuf_get_height)(pixbuf) == height - && (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf) == 8 - && (*fp_gdk_pixbuf_get_colorspace)(pixbuf) == GDK_COLORSPACE_RGB - && nchan >= 3 - ) { - guchar *p, *pix = (*fp_gdk_pixbuf_get_pixels)(pixbuf); - - ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL); - if (!ary) { - (*fp_g_object_unref)(pixbuf); - (*fp_gdk_threads_leave)(); - AWT_UNLOCK(); - return; - } - - for (_y = 0; _y < height; _y++) { - for (_x = 0; _x < width; _x++) { - p = pix + _y * stride + _x * nchan; - - index = (_y + dy) * jwidth + (_x + dx); - ary[index] = 0xff000000 - | (p[0] << 16) - | (p[1] << 8) - | (p[2]); - - } - } - (*env)->ReleasePrimitiveArrayCritical(env, pixelArray, ary, 0); - if ((*env)->ExceptionCheck(env)) { - (*fp_g_object_unref)(pixbuf); - (*fp_gdk_threads_leave)(); - AWT_UNLOCK(); - return; - } - gtk_failed = FALSE; - } - (*fp_g_object_unref)(pixbuf); - } - (*fp_gdk_threads_leave)(); + gtk->gdk_threads_enter(); + gtk_failed = gtk->get_drawable_data(env, pixelArray, x, y, width, + jwidth, height, dx, dy, scale); + gtk->gdk_threads_leave(); } if (gtk_failed) { diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_UNIXToolkit.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_UNIXToolkit.c index c8b29f3bdcc..81e3423feec 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_UNIXToolkit.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_UNIXToolkit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. * 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 @@ #ifndef HEADLESS #include "awt.h" -#include "gtk2_interface.h" +#include "gtk_interface.h" #endif /* !HEADLESS */ @@ -45,13 +45,12 @@ static jmethodID icon_upcall_method = NULL; /* * Class: sun_awt_UNIXToolkit * Method: check_gtk - * Signature: ()Z + * Signature: (I)Z */ JNIEXPORT jboolean JNICALL -Java_sun_awt_UNIXToolkit_check_1gtk(JNIEnv *env, jclass klass) -{ +Java_sun_awt_UNIXToolkit_check_1gtk(JNIEnv *env, jclass klass, jint version) { #ifndef HEADLESS - return (jboolean)gtk2_check_version(); + return (jboolean)gtk_check_version(version); #else return JNI_FALSE; #endif /* !HEADLESS */ @@ -61,13 +60,13 @@ Java_sun_awt_UNIXToolkit_check_1gtk(JNIEnv *env, jclass klass) /* * Class: sun_awt_UNIXToolkit * Method: load_gtk - * Signature: ()Z + * Signature: (I)Z */ JNIEXPORT jboolean JNICALL -Java_sun_awt_UNIXToolkit_load_1gtk(JNIEnv *env, jclass klass) -{ +Java_sun_awt_UNIXToolkit_load_1gtk(JNIEnv *env, jclass klass, jint version, + jboolean verbose) { #ifndef HEADLESS - return (jboolean)gtk2_load(env); + return (jboolean)gtk_load(env, version, verbose); #else return JNI_FALSE; #endif /* !HEADLESS */ @@ -83,16 +82,14 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_UNIXToolkit_unload_1gtk(JNIEnv *env, jclass klass) { #ifndef HEADLESS - return (jboolean)gtk2_unload(); + return (jboolean)gtk->unload(); #else return JNI_FALSE; #endif /* !HEADLESS */ } -jboolean _icon_upcall(JNIEnv *env, jobject this, GdkPixbuf *pixbuf) +jboolean init_method(JNIEnv *env, jobject this) { - jboolean result = JNI_FALSE; - if (this_class == NULL) { this_class = (*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, this)); @@ -100,33 +97,7 @@ jboolean _icon_upcall(JNIEnv *env, jobject this, GdkPixbuf *pixbuf) "loadIconCallback", "([BIIIIIZ)V"); CHECK_NULL_RETURN(icon_upcall_method, JNI_FALSE); } - - if (pixbuf != NULL) - { - guchar *pixbuf_data = (*fp_gdk_pixbuf_get_pixels)(pixbuf); - int row_stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); - int width = (*fp_gdk_pixbuf_get_width)(pixbuf); - int height = (*fp_gdk_pixbuf_get_height)(pixbuf); - int bps = (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf); - int channels = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); - gboolean alpha = (*fp_gdk_pixbuf_get_has_alpha)(pixbuf); - - /* Copy the data array into a Java structure so we can pass it back. */ - jbyteArray data = (*env)->NewByteArray(env, (row_stride * height)); - JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); - - (*env)->SetByteArrayRegion(env, data, 0, (row_stride * height), - (jbyte *)pixbuf_data); - - /* Release the pixbuf. */ - (*fp_g_object_unref)(pixbuf); - - /* Call the callback method to create the image on the Java side. */ - (*env)->CallVoidMethod(env, this, icon_upcall_method, data, - width, height, row_stride, bps, channels, alpha); - result = JNI_TRUE; - } - return result; + return JNI_TRUE; } /* @@ -144,7 +115,6 @@ Java_sun_awt_UNIXToolkit_load_1gtk_1icon(JNIEnv *env, jobject this, int len; char *filename_str = NULL; GError **error = NULL; - GdkPixbuf *pixbuf; if (filename == NULL) { @@ -158,13 +128,17 @@ Java_sun_awt_UNIXToolkit_load_1gtk_1icon(JNIEnv *env, jobject this, JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); return JNI_FALSE; } + if (!init_method(env, this) ) { + return JNI_FALSE; + } (*env)->GetStringUTFRegion(env, filename, 0, len, filename_str); - pixbuf = (*fp_gdk_pixbuf_new_from_file)(filename_str, error); + jboolean result = gtk->get_file_icon_data(env, filename_str, error, + icon_upcall_method, this); /* Release the strings we've allocated. */ free(filename_str); - return _icon_upcall(env, this, pixbuf); + return result; #else /* HEADLESS */ return JNI_FALSE; #endif /* !HEADLESS */ @@ -186,7 +160,6 @@ Java_sun_awt_UNIXToolkit_load_1stock_1icon(JNIEnv *env, jobject this, int len; char *stock_id_str = NULL; char *detail_str = NULL; - GdkPixbuf *pixbuf; if (stock_id == NULL) { @@ -215,8 +188,12 @@ Java_sun_awt_UNIXToolkit_load_1stock_1icon(JNIEnv *env, jobject this, (*env)->GetStringUTFRegion(env, detail, 0, len, detail_str); } - pixbuf = gtk2_get_stock_icon(widget_type, stock_id_str, icon_size, - text_direction, detail_str); + if (!init_method(env, this) ) { + return JNI_FALSE; + } + jboolean result = gtk->get_icon_data(env, widget_type, stock_id_str, + icon_size, text_direction, detail_str, + icon_upcall_method, this); /* Release the strings we've allocated. */ free(stock_id_str); @@ -224,8 +201,7 @@ Java_sun_awt_UNIXToolkit_load_1stock_1icon(JNIEnv *env, jobject this, { free(detail_str); } - - return _icon_upcall(env, this, pixbuf); + return result; #else /* HEADLESS */ return JNI_FALSE; #endif /* !HEADLESS */ @@ -279,11 +255,25 @@ Java_sun_awt_UNIXToolkit_gtkCheckVersionImpl(JNIEnv *env, jobject this, { char *ret; - ret = fp_gtk_check_version(major, minor, micro); + ret = gtk->gtk_check_version(major, minor, micro); if (ret == NULL) { return TRUE; } - free(ret); return FALSE; } + +/* + * Class: sun_awt_UNIXToolkit + * Method: get_gtk_version + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_sun_awt_UNIXToolkit_get_1gtk_1version(JNIEnv *env, jclass klass) +{ +#ifndef HEADLESS + return gtk ? gtk->version : GTK_ANY; +#else + return GTK_ANY; +#endif /* !HEADLESS */ +} diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c index ef58feccd9b..672a8414d8d 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c @@ -35,52 +35,18 @@ #include #include "awt.h" -#define GTK2_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("gtk-x11-2.0", "0") -#define GTK2_LIB JNI_LIB_NAME("gtk-x11-2.0") #define GTHREAD_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("gthread-2.0", "0") #define GTHREAD_LIB JNI_LIB_NAME("gthread-2.0") -#define G_TYPE_INVALID G_TYPE_MAKE_FUNDAMENTAL (0) -#define G_TYPE_NONE G_TYPE_MAKE_FUNDAMENTAL (1) -#define G_TYPE_INTERFACE G_TYPE_MAKE_FUNDAMENTAL (2) -#define G_TYPE_CHAR G_TYPE_MAKE_FUNDAMENTAL (3) -#define G_TYPE_UCHAR G_TYPE_MAKE_FUNDAMENTAL (4) -#define G_TYPE_BOOLEAN G_TYPE_MAKE_FUNDAMENTAL (5) -#define G_TYPE_INT G_TYPE_MAKE_FUNDAMENTAL (6) -#define G_TYPE_UINT G_TYPE_MAKE_FUNDAMENTAL (7) -#define G_TYPE_LONG G_TYPE_MAKE_FUNDAMENTAL (8) -#define G_TYPE_ULONG G_TYPE_MAKE_FUNDAMENTAL (9) -#define G_TYPE_INT64 G_TYPE_MAKE_FUNDAMENTAL (10) -#define G_TYPE_UINT64 G_TYPE_MAKE_FUNDAMENTAL (11) -#define G_TYPE_ENUM G_TYPE_MAKE_FUNDAMENTAL (12) -#define G_TYPE_FLAGS G_TYPE_MAKE_FUNDAMENTAL (13) -#define G_TYPE_FLOAT G_TYPE_MAKE_FUNDAMENTAL (14) -#define G_TYPE_DOUBLE G_TYPE_MAKE_FUNDAMENTAL (15) -#define G_TYPE_STRING G_TYPE_MAKE_FUNDAMENTAL (16) -#define G_TYPE_POINTER G_TYPE_MAKE_FUNDAMENTAL (17) -#define G_TYPE_BOXED G_TYPE_MAKE_FUNDAMENTAL (18) -#define G_TYPE_PARAM G_TYPE_MAKE_FUNDAMENTAL (19) -#define G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20) - #define GTK_TYPE_BORDER ((*fp_gtk_border_get_type)()) #define G_TYPE_FUNDAMENTAL_SHIFT (2) #define G_TYPE_MAKE_FUNDAMENTAL(x) ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT)) -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define CONV_BUFFER_SIZE 128 #define NO_SYMBOL_EXCEPTION 1 -/* SynthConstants */ -const gint ENABLED = 1 << 0; -const gint MOUSE_OVER = 1 << 1; -const gint PRESSED = 1 << 2; -const gint DISABLED = 1 << 3; -const gint FOCUSED = 1 << 8; -const gint SELECTED = 1 << 9; -const gint DEFAULT = 1 << 10; - static void *gtk2_libhandle = NULL; static void *gthread_libhandle = NULL; @@ -105,54 +71,6 @@ static char convertionBuffer[CONV_BUFFER_SIZE]; static gboolean new_combo = TRUE; const char ENV_PREFIX[] = "GTK_MODULES="; -/*******************/ -enum GtkWidgetType -{ - _GTK_ARROW_TYPE, - _GTK_BUTTON_TYPE, - _GTK_CHECK_BUTTON_TYPE, - _GTK_CHECK_MENU_ITEM_TYPE, - _GTK_COLOR_SELECTION_DIALOG_TYPE, - _GTK_COMBO_BOX_TYPE, - _GTK_COMBO_BOX_ARROW_BUTTON_TYPE, - _GTK_COMBO_BOX_TEXT_FIELD_TYPE, - _GTK_CONTAINER_TYPE, - _GTK_ENTRY_TYPE, - _GTK_FRAME_TYPE, - _GTK_HANDLE_BOX_TYPE, - _GTK_HPANED_TYPE, - _GTK_HPROGRESS_BAR_TYPE, - _GTK_HSCALE_TYPE, - _GTK_HSCROLLBAR_TYPE, - _GTK_HSEPARATOR_TYPE, - _GTK_IMAGE_TYPE, - _GTK_MENU_TYPE, - _GTK_MENU_BAR_TYPE, - _GTK_MENU_ITEM_TYPE, - _GTK_NOTEBOOK_TYPE, - _GTK_LABEL_TYPE, - _GTK_RADIO_BUTTON_TYPE, - _GTK_RADIO_MENU_ITEM_TYPE, - _GTK_SCROLLED_WINDOW_TYPE, - _GTK_SEPARATOR_MENU_ITEM_TYPE, - _GTK_SEPARATOR_TOOL_ITEM_TYPE, - _GTK_SPIN_BUTTON_TYPE, - _GTK_TEXT_VIEW_TYPE, - _GTK_TOGGLE_BUTTON_TYPE, - _GTK_TOOLBAR_TYPE, - _GTK_TOOLTIP_TYPE, - _GTK_TREE_VIEW_TYPE, - _GTK_VIEWPORT_TYPE, - _GTK_VPANED_TYPE, - _GTK_VPROGRESS_BAR_TYPE, - _GTK_VSCALE_TYPE, - _GTK_VSCROLLBAR_TYPE, - _GTK_VSEPARATOR_TYPE, - _GTK_WINDOW_TYPE, - _GTK_DIALOG_TYPE, - _GTK_WIDGET_TYPE_SIZE -}; - static GtkWidget *gtk2_widgets[_GTK_WIDGET_TYPE_SIZE]; @@ -359,20 +277,6 @@ static void (*fp_gtk_widget_size_request)(GtkWidget *widget, static GtkAdjustment* (*fp_gtk_range_get_adjustment)(GtkRange* range); /* Method bodies */ -const char *getStrFor(JNIEnv *env, jstring val) -{ - int length = (*env)->GetStringLength(env, val); - if (length > CONV_BUFFER_SIZE-1) - { - length = CONV_BUFFER_SIZE-1; -#ifdef DEBUG - fprintf(stderr, "Note: Detail is too long: %d chars\n", length); -#endif /* DEBUG */ - } - - (*env)->GetStringUTFRegion(env, val, 0, length, convertionBuffer); - return convertionBuffer; -} static void throw_exception(JNIEnv *env, const char* name, const char* message) { @@ -408,33 +312,34 @@ static void* dl_symbol_gthread(const char* name) return result; } -gboolean gtk2_check_version() +gboolean gtk2_check(const char* lib_name, int flags) { if (gtk2_libhandle != NULL) { /* We've already successfully opened the GTK libs, so return true. */ return TRUE; } else { void *lib = NULL; - gboolean result = FALSE; - lib = dlopen(GTK2_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL); + lib = dlopen(lib_name, flags); + if (lib == NULL) { - lib = dlopen(GTK2_LIB, RTLD_LAZY | RTLD_LOCAL); - if (lib == NULL) { - return FALSE; - } + return FALSE; + } + + if (flags & RTLD_NOLOAD) { + return TRUE; } fp_gtk_check_version = dlsym(lib, "gtk_check_version"); /* Check for GTK 2.2+ */ if (!fp_gtk_check_version(2, 2, 0)) { - result = TRUE; + return TRUE; } // 8048289: workaround for https://bugzilla.gnome.org/show_bug.cgi?id=733065 // dlclose(lib); - return result; + return FALSE; } } @@ -450,7 +355,7 @@ do { \ } while(0); -void update_supported_actions(JNIEnv *env) { +static void update_supported_actions(JNIEnv *env) { GVfs * (*fp_g_vfs_get_default) (void); const gchar * const * (*fp_g_vfs_get_supported_uri_schemes) (GVfs * vfs); const gchar * const * schemes = NULL; @@ -513,7 +418,7 @@ void update_supported_actions(JNIEnv *env) { /** * Functions for awt_Desktop.c */ -gboolean gtk2_show_uri_load(JNIEnv *env) { +static gboolean gtk2_show_uri_load(JNIEnv *env) { gboolean success = FALSE; dlerror(); const char *gtk_version = fp_gtk_check_version(2, 14, 0); @@ -547,7 +452,7 @@ gboolean gtk2_show_uri_load(JNIEnv *env) { /** * Functions for sun_awt_X11_GtkFileDialogPeer.c */ -void gtk2_file_chooser_load() +static void gtk2_file_chooser_load() { fp_gtk_file_chooser_get_filename = dl_symbol( "gtk_file_chooser_get_filename"); @@ -576,7 +481,7 @@ void gtk2_file_chooser_load() fp_gdk_x11_drawable_get_xid = dl_symbol("gdk_x11_drawable_get_xid"); } -gboolean gtk2_load(JNIEnv *env) +GtkApi* gtk2_load(JNIEnv *env, const char* lib_name) { gboolean result; int i; @@ -584,11 +489,9 @@ gboolean gtk2_load(JNIEnv *env) int (*io_handler)(); char *gtk_modules_env; - gtk2_libhandle = dlopen(GTK2_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL); + gtk2_libhandle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL); if (gtk2_libhandle == NULL) { - gtk2_libhandle = dlopen(GTK2_LIB, RTLD_LAZY | RTLD_LOCAL); - if (gtk2_libhandle == NULL) - return FALSE; + return FALSE; } gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL); @@ -962,8 +865,12 @@ gboolean gtk2_load(JNIEnv *env) { gtk2_widgets[i] = NULL; } - - return result; + if (result) { + GtkApi* gtk = (GtkApi*)malloc(sizeof(GtkApi)); + gtk2_init(gtk); + return gtk; + } + return NULL; } int gtk2_unload() @@ -1007,7 +914,7 @@ int gtk2_unload() /* Dispatch all pending events from the GTK event loop. * This is needed to catch theme change and update widgets' style. */ -void flush_gtk_event_loop() +static void flush_gtk_event_loop() { while( (*fp_g_main_context_iteration)(NULL, FALSE)); } @@ -1056,7 +963,7 @@ static void init_containers() * comparing results. This can be optimized by using subclassed pixmap and * doing the second drawing only if necessary. */ -void gtk2_init_painting(JNIEnv *env, gint width, gint height) +static void gtk2_init_painting(JNIEnv *env, gint width, gint height) { GdkGC *gc; GdkPixbuf *white, *black; @@ -1116,7 +1023,7 @@ void gtk2_init_painting(JNIEnv *env, gint width, gint height) * one of java_awt_Transparency_OPAQUE, java_awt_Transparency_BITMASK, and * java_awt_Transparency_TRANSLUCENT. */ -gint gtk2_copy_image(gint *dst, gint width, gint height) +static gint gtk2_copy_image(gint *dst, gint width, gint height) { gint i, j, r, g, b; guchar *white, *black; @@ -1778,7 +1685,7 @@ void gtk2_paint_arrow(WidgetType widget_type, GtkStateType state_type, x, y, w, h); } -void gtk2_paint_box(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_box(WidgetType widget_type, GtkStateType state_type, GtkShadowType shadow_type, const gchar *detail, gint x, gint y, gint width, gint height, gint synth_state, GtkTextDirection dir) @@ -1948,7 +1855,7 @@ void gtk2_paint_box_gap(WidgetType widget_type, GtkStateType state_type, x, y, width, height, gap_side, gap_x, gap_width); } -void gtk2_paint_check(WidgetType widget_type, gint synth_state, +static void gtk2_paint_check(WidgetType widget_type, gint synth_state, const gchar *detail, gint x, gint y, gint width, gint height) { GtkStateType state_type = get_gtk_state_type(widget_type, synth_state); @@ -1965,7 +1872,7 @@ void gtk2_paint_check(WidgetType widget_type, gint synth_state, x, y, width, height); } -void gtk2_paint_diamond(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_diamond(WidgetType widget_type, GtkStateType state_type, GtkShadowType shadow_type, const gchar *detail, gint x, gint y, gint width, gint height) { @@ -1978,7 +1885,7 @@ void gtk2_paint_diamond(WidgetType widget_type, GtkStateType state_type, x, y, width, height); } -void gtk2_paint_expander(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_expander(WidgetType widget_type, GtkStateType state_type, const gchar *detail, gint x, gint y, gint width, gint height, GtkExpanderStyle expander_style) { @@ -1991,7 +1898,7 @@ void gtk2_paint_expander(WidgetType widget_type, GtkStateType state_type, x + width / 2, y + height / 2, expander_style); } -void gtk2_paint_extension(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_extension(WidgetType widget_type, GtkStateType state_type, GtkShadowType shadow_type, const gchar *detail, gint x, gint y, gint width, gint height, GtkPositionType gap_side) { @@ -2004,7 +1911,7 @@ void gtk2_paint_extension(WidgetType widget_type, GtkStateType state_type, x, y, width, height, gap_side); } -void gtk2_paint_flat_box(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_flat_box(WidgetType widget_type, GtkStateType state_type, GtkShadowType shadow_type, const gchar *detail, gint x, gint y, gint width, gint height, gboolean has_focus) { @@ -2023,7 +1930,7 @@ void gtk2_paint_flat_box(WidgetType widget_type, GtkStateType state_type, x, y, width, height); } -void gtk2_paint_focus(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_focus(WidgetType widget_type, GtkStateType state_type, const char *detail, gint x, gint y, gint width, gint height) { gtk2_widget = gtk2_get_widget(widget_type); @@ -2033,7 +1940,7 @@ void gtk2_paint_focus(WidgetType widget_type, GtkStateType state_type, NULL, gtk2_widget, detail, x, y, width, height); } -void gtk2_paint_handle(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_handle(WidgetType widget_type, GtkStateType state_type, GtkShadowType shadow_type, const gchar *detail, gint x, gint y, gint width, gint height, GtkOrientation orientation) { @@ -2046,7 +1953,7 @@ void gtk2_paint_handle(WidgetType widget_type, GtkStateType state_type, x, y, width, height, orientation); } -void gtk2_paint_hline(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_hline(WidgetType widget_type, GtkStateType state_type, const gchar *detail, gint x, gint y, gint width, gint height) { gtk2_widget = gtk2_get_widget(widget_type); @@ -2056,7 +1963,7 @@ void gtk2_paint_hline(WidgetType widget_type, GtkStateType state_type, NULL, gtk2_widget, detail, x, x + width, y); } -void gtk2_paint_option(WidgetType widget_type, gint synth_state, +static void gtk2_paint_option(WidgetType widget_type, gint synth_state, const gchar *detail, gint x, gint y, gint width, gint height) { GtkStateType state_type = get_gtk_state_type(widget_type, synth_state); @@ -2073,7 +1980,7 @@ void gtk2_paint_option(WidgetType widget_type, gint synth_state, x, y, width, height); } -void gtk2_paint_shadow(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_shadow(WidgetType widget_type, GtkStateType state_type, GtkShadowType shadow_type, const gchar *detail, gint x, gint y, gint width, gint height, gint synth_state, GtkTextDirection dir) @@ -2123,9 +2030,10 @@ void gtk2_paint_shadow(WidgetType widget_type, GtkStateType state_type, gtk2_set_direction(gtk2_widget, GTK_TEXT_DIR_LTR); } -void gtk2_paint_slider(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_slider(WidgetType widget_type, GtkStateType state_type, GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, GtkOrientation orientation) + gint x, gint y, gint width, gint height, GtkOrientation orientation, + gboolean has_focus) { gtk2_widget = gtk2_get_widget(widget_type); (*fp_gtk_paint_slider)(gtk2_widget->style, gtk2_white_pixmap, state_type, @@ -2136,7 +2044,7 @@ void gtk2_paint_slider(WidgetType widget_type, GtkStateType state_type, x, y, width, height, orientation); } -void gtk2_paint_vline(WidgetType widget_type, GtkStateType state_type, +static void gtk2_paint_vline(WidgetType widget_type, GtkStateType state_type, const gchar *detail, gint x, gint y, gint width, gint height) { gtk2_widget = gtk2_get_widget(widget_type); @@ -2146,7 +2054,7 @@ void gtk2_paint_vline(WidgetType widget_type, GtkStateType state_type, NULL, gtk2_widget, detail, y, y + height, x); } -void gtk_paint_background(WidgetType widget_type, GtkStateType state_type, +static void gtk_paint_background(WidgetType widget_type, GtkStateType state_type, gint x, gint y, gint width, gint height) { gtk2_widget = gtk2_get_widget(widget_type); @@ -2156,7 +2064,7 @@ void gtk_paint_background(WidgetType widget_type, GtkStateType state_type, gtk2_black_pixmap, TRUE, state_type, NULL, x, y, width, height); } -GdkPixbuf *gtk2_get_stock_icon(gint widget_type, const gchar *stock_id, +static GdkPixbuf *gtk2_get_stock_icon(gint widget_type, const gchar *stock_id, GtkIconSize size, GtkTextDirection direction, const char *detail) { init_containers(); @@ -2166,8 +2074,52 @@ GdkPixbuf *gtk2_get_stock_icon(gint widget_type, const gchar *stock_id, return (*fp_gtk_widget_render_icon)(gtk2_widget, stock_id, size, detail); } +static jboolean gtk2_get_pixbuf_data(JNIEnv *env, GdkPixbuf* pixbuf, + jmethodID icon_upcall_method, jobject this) { + if (!pixbuf) { + return JNI_FALSE; + } + guchar *pixbuf_data = (*fp_gdk_pixbuf_get_pixels)(pixbuf); + if (pixbuf_data) { + int row_stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); + int width = (*fp_gdk_pixbuf_get_width)(pixbuf); + int height = (*fp_gdk_pixbuf_get_height)(pixbuf); + int bps = (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf); + int channels = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); + gboolean alpha = (*fp_gdk_pixbuf_get_has_alpha)(pixbuf); + + jbyteArray data = (*env)->NewByteArray(env, (row_stride * height)); + JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); + + (*env)->SetByteArrayRegion(env, data, 0, (row_stride * height), + (jbyte *)pixbuf_data); + (*fp_g_object_unref)(pixbuf); + + /* Call the callback method to create the image on the Java side. */ + (*env)->CallVoidMethod(env, this, icon_upcall_method, data, + width, height, row_stride, bps, channels, alpha); + return JNI_TRUE; + } + return JNI_FALSE; +} + +static jboolean gtk2_get_file_icon_data(JNIEnv *env, const char *filename, + GError **error, jmethodID icon_upcall_method, jobject this) { + GdkPixbuf* pixbuf = fp_gdk_pixbuf_new_from_file(filename, error); + return gtk2_get_pixbuf_data(env, pixbuf, icon_upcall_method, this); +} + +static jboolean gtk2_get_icon_data(JNIEnv *env, gint widget_type, + const gchar *stock_id, GtkIconSize size, + GtkTextDirection direction, const char *detail, + jmethodID icon_upcall_method, jobject this) { + GdkPixbuf* pixbuf = gtk2_get_stock_icon(widget_type, stock_id, size, + direction, detail); + return gtk2_get_pixbuf_data(env, pixbuf, icon_upcall_method, this); +} + /*************************************************/ -gint gtk2_get_xthickness(JNIEnv *env, WidgetType widget_type) +static gint gtk2_get_xthickness(JNIEnv *env, WidgetType widget_type) { init_containers(); @@ -2176,7 +2128,7 @@ gint gtk2_get_xthickness(JNIEnv *env, WidgetType widget_type) return style->xthickness; } -gint gtk2_get_ythickness(JNIEnv *env, WidgetType widget_type) +static gint gtk2_get_ythickness(JNIEnv *env, WidgetType widget_type) { init_containers(); @@ -2186,12 +2138,12 @@ gint gtk2_get_ythickness(JNIEnv *env, WidgetType widget_type) } /*************************************************/ -guint8 recode_color(guint16 channel) +static guint8 recode_color(guint16 channel) { return (guint8)(channel>>8); } -gint gtk2_get_color_for_state(JNIEnv *env, WidgetType widget_type, +static gint gtk2_get_color_for_state(JNIEnv *env, WidgetType widget_type, GtkStateType state_type, ColorType color_type) { gint result = 0; @@ -2243,19 +2195,19 @@ gint gtk2_get_color_for_state(JNIEnv *env, WidgetType widget_type, } /*************************************************/ -jobject create_Boolean(JNIEnv *env, jboolean boolean_value); -jobject create_Integer(JNIEnv *env, jint int_value); -jobject create_Long(JNIEnv *env, jlong long_value); -jobject create_Float(JNIEnv *env, jfloat float_value); -jobject create_Double(JNIEnv *env, jdouble double_value); -jobject create_Character(JNIEnv *env, jchar char_value); -jobject create_Insets(JNIEnv *env, GtkBorder *border); +static jobject create_Boolean(JNIEnv *env, jboolean boolean_value); +static jobject create_Integer(JNIEnv *env, jint int_value); +static jobject create_Long(JNIEnv *env, jlong long_value); +static jobject create_Float(JNIEnv *env, jfloat float_value); +static jobject create_Double(JNIEnv *env, jdouble double_value); +static jobject create_Character(JNIEnv *env, jchar char_value); +static jobject create_Insets(JNIEnv *env, GtkBorder *border); -jobject gtk2_get_class_value(JNIEnv *env, WidgetType widget_type, jstring jkey) +static jobject gtk2_get_class_value(JNIEnv *env, WidgetType widget_type, + const char* key) { init_containers(); - const char* key = getStrFor(env, jkey); gtk2_widget = gtk2_get_widget(widget_type); GValue value; @@ -2376,7 +2328,7 @@ jobject gtk2_get_class_value(JNIEnv *env, WidgetType widget_type, jstring jkey) return NULL; } -void gtk2_set_range_value(WidgetType widget_type, jdouble value, +static void gtk2_set_range_value(WidgetType widget_type, jdouble value, jdouble min, jdouble max, jdouble visible) { GtkAdjustment *adj; @@ -2391,7 +2343,7 @@ void gtk2_set_range_value(WidgetType widget_type, jdouble value, } /*************************************************/ -jobject create_Object(JNIEnv *env, jmethodID *cid, +static jobject create_Object(JNIEnv *env, jmethodID *cid, const char* class_name, const char* signature, jvalue* value) @@ -2494,7 +2446,7 @@ jobject create_Insets(JNIEnv *env, GtkBorder *border) } /*********************************************/ -jstring gtk2_get_pango_font_name(JNIEnv *env, WidgetType widget_type) +static jstring gtk2_get_pango_font_name(JNIEnv *env, WidgetType widget_type) { init_containers(); @@ -2513,7 +2465,7 @@ jstring gtk2_get_pango_font_name(JNIEnv *env, WidgetType widget_type) } /***********************************************/ -jobject get_string_property(JNIEnv *env, GtkSettings* settings, const gchar* key) +static jobject get_string_property(JNIEnv *env, GtkSettings* settings, const gchar* key) { jobject result = NULL; gchar* strval = NULL; @@ -2525,21 +2477,21 @@ jobject get_string_property(JNIEnv *env, GtkSettings* settings, const gchar* key return result; } -jobject get_integer_property(JNIEnv *env, GtkSettings* settings, const gchar* key) +static jobject get_integer_property(JNIEnv *env, GtkSettings* settings, const gchar* key) { gint intval = NULL; (*fp_g_object_get)(settings, key, &intval, NULL); return create_Integer(env, intval); } -jobject get_boolean_property(JNIEnv *env, GtkSettings* settings, const gchar* key) +static jobject get_boolean_property(JNIEnv *env, GtkSettings* settings, const gchar* key) { gint intval = NULL; (*fp_g_object_get)(settings, key, &intval, NULL); return create_Boolean(env, intval); } -jobject gtk2_get_setting(JNIEnv *env, Setting property) +static jobject gtk2_get_setting(JNIEnv *env, Setting property) { GtkSettings* settings = (*fp_gtk_settings_get_default)(); @@ -2557,3 +2509,148 @@ jobject gtk2_get_setting(JNIEnv *env, Setting property) return NULL; } + +static gboolean gtk2_get_drawable_data(JNIEnv *env, jintArray pixelArray, jint x, + jint y, jint width, jint height, jint jwidth, int dx, int dy, jint scale) { + GdkPixbuf *pixbuf; + jint *ary; + + GdkWindow *root = (*fp_gdk_get_default_root_window)(); + + pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(NULL, root, NULL, x, y, + 0, 0, width, height); + if (pixbuf && scale != 1) { + GdkPixbuf *scaledPixbuf; + x /= scale; + y /= scale; + width /= scale; + height /= scale; + dx /= scale; + dy /= scale; + scaledPixbuf = (*fp_gdk_pixbuf_scale_simple)(pixbuf, width, height, + GDK_INTERP_BILINEAR); + (*fp_g_object_unref)(pixbuf); + pixbuf = scaledPixbuf; + } + + if (pixbuf) { + int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); + int stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); + + if ((*fp_gdk_pixbuf_get_width)(pixbuf) == width + && (*fp_gdk_pixbuf_get_height)(pixbuf) == height + && (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf) == 8 + && (*fp_gdk_pixbuf_get_colorspace)(pixbuf) == GDK_COLORSPACE_RGB + && nchan >= 3 + ) { + guchar *p, *pix = (*fp_gdk_pixbuf_get_pixels)(pixbuf); + + ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL); + if (ary) { + jint _x, _y; + int index; + for (_y = 0; _y < height; _y++) { + for (_x = 0; _x < width; _x++) { + p = pix + _y * stride + _x * nchan; + + index = (_y + dy) * jwidth + (_x + dx); + ary[index] = 0xff000000 + | (p[0] << 16) + | (p[1] << 8) + | (p[2]); + + } + } + (*env)->ReleasePrimitiveArrayCritical(env, pixelArray, ary, 0); + } + } + (*fp_g_object_unref)(pixbuf); + } + return JNI_FALSE; +} + +static GdkWindow* gtk2_get_window(void *widget) { + return ((GtkWidget*)widget)->window; +} + +void gtk2_init(GtkApi* gtk) { + gtk->version = GTK_2; + + gtk->show_uri_load = >k2_show_uri_load; + gtk->unload = >k2_unload; + gtk->flush_event_loop = &flush_gtk_event_loop; + gtk->gtk_check_version = fp_gtk_check_version; + gtk->get_setting = >k2_get_setting; + + gtk->paint_arrow = >k2_paint_arrow; + gtk->paint_box = >k2_paint_box; + gtk->paint_box_gap = >k2_paint_box_gap; + gtk->paint_expander = >k2_paint_expander; + gtk->paint_extension = >k2_paint_extension; + gtk->paint_flat_box = >k2_paint_flat_box; + gtk->paint_focus = >k2_paint_focus; + gtk->paint_handle = >k2_paint_handle; + gtk->paint_hline = >k2_paint_hline; + gtk->paint_vline = >k2_paint_vline; + gtk->paint_option = >k2_paint_option; + gtk->paint_shadow = >k2_paint_shadow; + gtk->paint_slider = >k2_paint_slider; + gtk->paint_background = >k_paint_background; + gtk->paint_check = >k2_paint_check; + gtk->set_range_value = >k2_set_range_value; + + gtk->init_painting = >k2_init_painting; + gtk->copy_image = >k2_copy_image; + + gtk->get_xthickness = >k2_get_xthickness; + gtk->get_ythickness = >k2_get_ythickness; + gtk->get_color_for_state = >k2_get_color_for_state; + gtk->get_class_value = >k2_get_class_value; + + gtk->get_pango_font_name = >k2_get_pango_font_name; + gtk->get_icon_data = >k2_get_icon_data; + gtk->get_file_icon_data = >k2_get_file_icon_data; + gtk->gdk_threads_enter = fp_gdk_threads_enter; + gtk->gdk_threads_leave = fp_gdk_threads_leave; + gtk->gtk_show_uri = fp_gtk_show_uri; + gtk->get_drawable_data = >k2_get_drawable_data; + gtk->g_free = fp_g_free; + + gtk->gtk_file_chooser_get_filename = fp_gtk_file_chooser_get_filename; + gtk->gtk_widget_hide = fp_gtk_widget_hide; + gtk->gtk_main_quit = fp_gtk_main_quit; + gtk->gtk_file_chooser_dialog_new = fp_gtk_file_chooser_dialog_new; + gtk->gtk_file_chooser_set_current_folder = + fp_gtk_file_chooser_set_current_folder; + gtk->gtk_file_chooser_set_filename = fp_gtk_file_chooser_set_filename; + gtk->gtk_file_chooser_set_current_name = + fp_gtk_file_chooser_set_current_name; + gtk->gtk_file_filter_add_custom = fp_gtk_file_filter_add_custom; + gtk->gtk_file_chooser_set_filter = fp_gtk_file_chooser_set_filter; + gtk->gtk_file_chooser_get_type = fp_gtk_file_chooser_get_type; + gtk->gtk_file_filter_new = fp_gtk_file_filter_new; + gtk->gtk_file_chooser_set_do_overwrite_confirmation = + fp_gtk_file_chooser_set_do_overwrite_confirmation; + gtk->gtk_file_chooser_set_select_multiple = + fp_gtk_file_chooser_set_select_multiple; + gtk->gtk_file_chooser_get_current_folder = + fp_gtk_file_chooser_get_current_folder; + gtk->gtk_file_chooser_get_filenames = fp_gtk_file_chooser_get_filenames; + gtk->gtk_g_slist_length = fp_gtk_g_slist_length; + gtk->g_signal_connect_data = fp_g_signal_connect_data; + gtk->gtk_widget_show = fp_gtk_widget_show; + gtk->gtk_main = fp_gtk_main; + gtk->gtk_main_level = fp_gtk_main_level; + gtk->g_path_get_dirname = fp_g_path_get_dirname; + gtk->gdk_x11_drawable_get_xid = fp_gdk_x11_drawable_get_xid; + gtk->gtk_widget_destroy = fp_gtk_widget_destroy; + gtk->gtk_window_present = fp_gtk_window_present; + gtk->gtk_window_move = fp_gtk_window_move; + gtk->gtk_window_resize = fp_gtk_window_resize; + gtk->get_window = >k2_get_window; + + gtk->g_object_unref = fp_g_object_unref; + gtk->g_list_append = fp_g_list_append; + gtk->g_list_free = fp_g_list_free; + gtk->g_list_free_full = fp_g_list_free_full; +} diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h index c94749ecb51..b405e070f43 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h @@ -28,232 +28,11 @@ #include #include #include - -#define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip) -#define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) (_G_TYPE_CIC ((instance), (g_type), c_type)) -#define GTK_TYPE_FILE_CHOOSER (fp_gtk_file_chooser_get_type ()) -#define GTK_FILE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_CHOOSER, GtkFileChooser)) -#define fp_g_signal_connect(instance, detailed_signal, c_handler, data) \ - fp_g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) -#define G_CALLBACK(f) ((GCallback) (f)) -#define G_TYPE_FUNDAMENTAL_SHIFT (2) -#define G_TYPE_MAKE_FUNDAMENTAL(x) ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT)) -#define G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20) -#define G_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_OBJECT, GObject)) -#define GTK_STOCK_CANCEL "gtk-cancel" -#define GTK_STOCK_SAVE "gtk-save" -#define GTK_STOCK_OPEN "gtk-open" -#define GDK_CURRENT_TIME 0L - -typedef enum _WidgetType -{ - BUTTON, /* GtkButton */ - CHECK_BOX, /* GtkCheckButton */ - CHECK_BOX_MENU_ITEM, /* GtkCheckMenuItem */ - COLOR_CHOOSER, /* GtkColorSelectionDialog */ - COMBO_BOX, /* GtkComboBox */ - COMBO_BOX_ARROW_BUTTON, /* GtkComboBoxEntry */ - COMBO_BOX_TEXT_FIELD, /* GtkComboBoxEntry */ - DESKTOP_ICON, /* GtkLabel */ - DESKTOP_PANE, /* GtkContainer */ - EDITOR_PANE, /* GtkTextView */ - FORMATTED_TEXT_FIELD, /* GtkEntry */ - HANDLE_BOX, /* GtkHandleBox */ - HPROGRESS_BAR, /* GtkProgressBar */ - HSCROLL_BAR, /* GtkHScrollbar */ - HSCROLL_BAR_BUTTON_LEFT, /* GtkHScrollbar */ - HSCROLL_BAR_BUTTON_RIGHT, /* GtkHScrollbar */ - HSCROLL_BAR_TRACK, /* GtkHScrollbar */ - HSCROLL_BAR_THUMB, /* GtkHScrollbar */ - HSEPARATOR, /* GtkHSeparator */ - HSLIDER, /* GtkHScale */ - HSLIDER_TRACK, /* GtkHScale */ - HSLIDER_THUMB, /* GtkHScale */ - HSPLIT_PANE_DIVIDER, /* GtkHPaned */ - INTERNAL_FRAME, /* GtkWindow */ - INTERNAL_FRAME_TITLE_PANE, /* GtkLabel */ - IMAGE, /* GtkImage */ - LABEL, /* GtkLabel */ - LIST, /* GtkTreeView */ - MENU, /* GtkMenu */ - MENU_BAR, /* GtkMenuBar */ - MENU_ITEM, /* GtkMenuItem */ - MENU_ITEM_ACCELERATOR, /* GtkLabel */ - OPTION_PANE, /* GtkMessageDialog */ - PANEL, /* GtkContainer */ - PASSWORD_FIELD, /* GtkEntry */ - POPUP_MENU, /* GtkMenu */ - POPUP_MENU_SEPARATOR, /* GtkSeparatorMenuItem */ - RADIO_BUTTON, /* GtkRadioButton */ - RADIO_BUTTON_MENU_ITEM, /* GtkRadioMenuItem */ - ROOT_PANE, /* GtkContainer */ - SCROLL_PANE, /* GtkScrolledWindow */ - SPINNER, /* GtkSpinButton */ - SPINNER_ARROW_BUTTON, /* GtkSpinButton */ - SPINNER_TEXT_FIELD, /* GtkSpinButton */ - SPLIT_PANE, /* GtkPaned */ - TABBED_PANE, /* GtkNotebook */ - TABBED_PANE_TAB_AREA, /* GtkNotebook */ - TABBED_PANE_CONTENT, /* GtkNotebook */ - TABBED_PANE_TAB, /* GtkNotebook */ - TABLE, /* GtkTreeView */ - TABLE_HEADER, /* GtkButton */ - TEXT_AREA, /* GtkTextView */ - TEXT_FIELD, /* GtkEntry */ - TEXT_PANE, /* GtkTextView */ - TITLED_BORDER, /* GtkFrame */ - TOGGLE_BUTTON, /* GtkToggleButton */ - TOOL_BAR, /* GtkToolbar */ - TOOL_BAR_DRAG_WINDOW, /* GtkToolbar */ - TOOL_BAR_SEPARATOR, /* GtkSeparatorToolItem */ - TOOL_TIP, /* GtkWindow */ - TREE, /* GtkTreeView */ - TREE_CELL, /* GtkTreeView */ - VIEWPORT, /* GtkViewport */ - VPROGRESS_BAR, /* GtkProgressBar */ - VSCROLL_BAR, /* GtkVScrollbar */ - VSCROLL_BAR_BUTTON_UP, /* GtkVScrollbar */ - VSCROLL_BAR_BUTTON_DOWN, /* GtkVScrollbar */ - VSCROLL_BAR_TRACK, /* GtkVScrollbar */ - VSCROLL_BAR_THUMB, /* GtkVScrollbar */ - VSEPARATOR, /* GtkVSeparator */ - VSLIDER, /* GtkVScale */ - VSLIDER_TRACK, /* GtkVScale */ - VSLIDER_THUMB, /* GtkVScale */ - VSPLIT_PANE_DIVIDER, /* GtkVPaned */ - WIDGET_TYPE_SIZE -} WidgetType; - -typedef enum _ColorType -{ - FOREGROUND, - BACKGROUND, - TEXT_FOREGROUND, - TEXT_BACKGROUND, - FOCUS, - LIGHT, - DARK, - MID, - BLACK, - WHITE -} ColorType; - -typedef enum _Setting -{ - GTK_FONT_NAME, - GTK_ICON_SIZES, - GTK_CURSOR_BLINK, - GTK_CURSOR_BLINK_TIME -} Setting; - -/* GTK types, here to eliminate need for GTK headers at compile time */ - -#ifndef FALSE -#define FALSE (0) -#define TRUE (!FALSE) -#endif +#include "gtk_interface.h" #define GTK_HAS_FOCUS (1 << 12) #define GTK_HAS_DEFAULT (1 << 14) - -/* basic types */ -typedef char gchar; -typedef short gshort; -typedef int gint; -typedef long glong; -typedef float gfloat; -typedef double gdouble; -typedef void* gpointer; -typedef gint gboolean; - -typedef signed char gint8; -typedef signed short gint16; -typedef signed int gint32; - -typedef unsigned char guchar; -typedef unsigned char guint8; -typedef unsigned short gushort; -typedef unsigned short guint16; -typedef unsigned int guint; -typedef unsigned int guint32; -typedef unsigned int gsize; -typedef unsigned long gulong; - -typedef signed long long gint64; -typedef unsigned long long guint64; - -/* enumerated constants */ -typedef enum -{ - GTK_ARROW_UP, - GTK_ARROW_DOWN, - GTK_ARROW_LEFT, - GTK_ARROW_RIGHT -} GtkArrowType; - -typedef enum { - GDK_COLORSPACE_RGB -} GdkColorspace; - -typedef enum -{ - GTK_EXPANDER_COLLAPSED, - GTK_EXPANDER_SEMI_COLLAPSED, - GTK_EXPANDER_SEMI_EXPANDED, - GTK_EXPANDER_EXPANDED -} GtkExpanderStyle; - -typedef enum -{ - GTK_ICON_SIZE_INVALID, - GTK_ICON_SIZE_MENU, - GTK_ICON_SIZE_SMALL_TOOLBAR, - GTK_ICON_SIZE_LARGE_TOOLBAR, - GTK_ICON_SIZE_BUTTON, - GTK_ICON_SIZE_DND, - GTK_ICON_SIZE_DIALOG -} GtkIconSize; - -typedef enum -{ - GTK_ORIENTATION_HORIZONTAL, - GTK_ORIENTATION_VERTICAL -} GtkOrientation; - -typedef enum -{ - GTK_POS_LEFT, - GTK_POS_RIGHT, - GTK_POS_TOP, - GTK_POS_BOTTOM -} GtkPositionType; - -typedef enum -{ - GTK_SHADOW_NONE, - GTK_SHADOW_IN, - GTK_SHADOW_OUT, - GTK_SHADOW_ETCHED_IN, - GTK_SHADOW_ETCHED_OUT -} GtkShadowType; - -typedef enum -{ - GTK_STATE_NORMAL, - GTK_STATE_ACTIVE, - GTK_STATE_PRELIGHT, - GTK_STATE_SELECTED, - GTK_STATE_INSENSITIVE -} GtkStateType; - -typedef enum -{ - GTK_TEXT_DIR_NONE, - GTK_TEXT_DIR_LTR, - GTK_TEXT_DIR_RTL -} GtkTextDirection; - typedef enum { GTK_WINDOW_TOPLEVEL, @@ -270,41 +49,15 @@ typedef enum G_PARAM_PRIVATE = 1 << 5 } GParamFlags; -typedef enum { - GDK_INTERP_NEAREST, - GDK_INTERP_TILES, - GDK_INTERP_BILINEAR, - GDK_INTERP_HYPER -} GdkInterpType; - /* We define all structure pointers to be void* */ -typedef void GError; typedef void GMainContext; typedef void GVfs; -typedef struct _GSList GSList; -struct _GSList -{ - gpointer data; - GSList *next; -}; - -typedef struct _GList GList; - -struct _GList -{ - gpointer data; - GList *next; - GList *prev; -}; - typedef void GdkColormap; typedef void GdkDrawable; typedef void GdkGC; -typedef void GdkScreen; typedef void GdkPixbuf; typedef void GdkPixmap; -typedef void GdkWindow; typedef void GtkFixed; typedef void GtkMenuItem; @@ -364,7 +117,6 @@ typedef struct { * structures. This is a place where getting rid of gtk * headers may be dangerous. ******************************************************/ -typedef gulong GType; typedef struct { @@ -599,70 +351,9 @@ struct _GtkProgressBar guint ellipsize : 3; }; -typedef enum { - GTK_RESPONSE_NONE = -1, - GTK_RESPONSE_REJECT = -2, - GTK_RESPONSE_ACCEPT = -3, - GTK_RESPONSE_DELETE_EVENT = -4, - GTK_RESPONSE_OK = -5, - GTK_RESPONSE_CANCEL = -6, - GTK_RESPONSE_CLOSE = -7, - GTK_RESPONSE_YES = -8, - GTK_RESPONSE_NO = -9, - GTK_RESPONSE_APPLY = -10, - GTK_RESPONSE_HELP = -11 -} GtkResponseType; - -typedef struct _GtkWindow GtkWindow; - -typedef struct _GtkFileChooser GtkFileChooser; - -typedef enum { - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, - GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER -} GtkFileChooserAction; - -typedef struct _GtkFileFilter GtkFileFilter; - -typedef enum { - GTK_FILE_FILTER_FILENAME = 1 << 0, - GTK_FILE_FILTER_URI = 1 << 1, - GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2, - GTK_FILE_FILTER_MIME_TYPE = 1 << 3 -} GtkFileFilterFlags; - -typedef struct { - GtkFileFilterFlags contains; - const gchar *filename; - const gchar *uri; - const gchar *display_name; - const gchar *mime_type; -} GtkFileFilterInfo; - -typedef gboolean (*GtkFileFilterFunc)(const GtkFileFilterInfo *filter_info, - gpointer data); - -typedef void (*GDestroyNotify)(gpointer data); - -typedef void (*GCallback)(void); - -typedef struct _GClosure GClosure; - -typedef void (*GClosureNotify)(gpointer data, GClosure *closure); - -typedef enum { - G_CONNECT_AFTER = 1 << 0, G_CONNECT_SWAPPED = 1 << 1 -} GConnectFlags; typedef struct _GThreadFunctions GThreadFunctions; -/* - * Converts java.lang.String object to UTF-8 character string. - */ -const char *getStrFor(JNIEnv *env, jstring value); - /** * Returns : * NULL if the GLib library is compatible with the given version, or a string @@ -670,7 +361,7 @@ const char *getStrFor(JNIEnv *env, jstring value); * Please note that the glib_check_version() is available since 2.6, * so you should use GLIB_CHECK_VERSION macro instead. */ -gchar* (*fp_glib_check_version)(guint required_major, guint required_minor, +static gchar* (*fp_glib_check_version)(guint required_major, guint required_minor, guint required_micro); /** @@ -680,193 +371,96 @@ gchar* (*fp_glib_check_version)(guint required_major, guint required_minor, #define GLIB_CHECK_VERSION(major, minor, micro) \ (fp_glib_check_version && fp_glib_check_version(major, minor, micro) == NULL) -/* - * Check whether the gtk2 library is available and meets the minimum - * version requirement. If the library is already loaded this method has no - * effect and returns success. - * Returns FALSE on failure and TRUE on success. - */ -gboolean gtk2_check_version(); - /** * Returns : * NULL if the GTK+ library is compatible with the given version, or a string * describing the version mismatch. */ -gchar* (*fp_gtk_check_version)(guint required_major, guint required_minor, +static gchar* (*fp_gtk_check_version)(guint required_major, guint required_minor, guint required_micro); -/* - * Load the gtk2 library. If the library is already loaded this method has no - * effect and returns success. - * Returns FALSE on failure and TRUE on success. - */ -gboolean gtk2_load(JNIEnv *env); -/* - * Loads fp_gtk_show_uri function pointer. This initialization is - * separated because the function is required only - * for java.awt.Desktop API. The function relies on initialization in - * gtk2_load, so it must be invoked only after a successful gtk2_load - * invocation - */ -gboolean gtk2_show_uri_load(JNIEnv *env); +static void gtk2_init(GtkApi* gtk); -/* - * Unload the gtk2 library. If the library is already unloaded this method has - * no effect and returns success. - * Returns FALSE on failure and TRUE on success. - */ -gboolean gtk2_unload(); +static void (*fp_g_free)(gpointer mem); +static void (*fp_g_object_unref)(gpointer object); +static GdkWindow *(*fp_gdk_get_default_root_window) (void); -void gtk2_paint_arrow(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, - GtkArrowType arrow_type, gboolean fill); -void gtk2_paint_box(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, - gint synth_state, GtkTextDirection dir); -void gtk2_paint_box_gap(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, - GtkPositionType gap_side, gint gap_x, gint gap_width); -void gtk2_paint_check(WidgetType widget_type, gint synth_state, - const gchar *detail, gint x, gint y, gint width, gint height); -void gtk2_paint_diamond(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height); -void gtk2_paint_expander(WidgetType widget_type, GtkStateType state_type, - const gchar *detail, gint x, gint y, gint width, gint height, - GtkExpanderStyle expander_style); -void gtk2_paint_extension(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, GtkPositionType gap_side); -void gtk2_paint_flat_box(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, gboolean has_focus); -void gtk2_paint_focus(WidgetType widget_type, GtkStateType state_type, - const char *detail, gint x, gint y, gint width, gint height); -void gtk2_paint_handle(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, GtkOrientation orientation); -void gtk2_paint_hline(WidgetType widget_type, GtkStateType state_type, - const gchar *detail, gint x, gint y, gint width, gint height); -void gtk2_paint_option(WidgetType widget_type, gint synth_state, - const gchar *detail, gint x, gint y, gint width, gint height); -void gtk2_paint_shadow(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, - gint synth_state, GtkTextDirection dir); -void gtk2_paint_slider(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, GtkOrientation orientation); -void gtk2_paint_vline(WidgetType widget_type, GtkStateType state_type, - const gchar *detail, gint x, gint y, gint width, gint height); -void gtk_paint_background(WidgetType widget_type, GtkStateType state_type, - gint x, gint y, gint width, gint height); +static int (*fp_gdk_pixbuf_get_bits_per_sample)(const GdkPixbuf *pixbuf); +static guchar *(*fp_gdk_pixbuf_get_pixels)(const GdkPixbuf *pixbuf); +static gboolean (*fp_gdk_pixbuf_get_has_alpha)(const GdkPixbuf *pixbuf); +static int (*fp_gdk_pixbuf_get_height)(const GdkPixbuf *pixbuf); +static int (*fp_gdk_pixbuf_get_n_channels)(const GdkPixbuf *pixbuf); +static int (*fp_gdk_pixbuf_get_rowstride)(const GdkPixbuf *pixbuf); +static int (*fp_gdk_pixbuf_get_width)(const GdkPixbuf *pixbuf); +static GdkPixbuf *(*fp_gdk_pixbuf_new_from_file)(const char *filename, GError **error); +static GdkColorspace (*fp_gdk_pixbuf_get_colorspace)(const GdkPixbuf *pixbuf); -void gtk2_init_painting(JNIEnv *env, gint w, gint h); -gint gtk2_copy_image(gint *dest, gint width, gint height); - -gint gtk2_get_xthickness(JNIEnv *env, WidgetType widget_type); -gint gtk2_get_ythickness(JNIEnv *env, WidgetType widget_type); -gint gtk2_get_color_for_state(JNIEnv *env, WidgetType widget_type, - GtkStateType state_type, ColorType color_type); -jobject gtk2_get_class_value(JNIEnv *env, WidgetType widget_type, jstring key); - -GdkPixbuf *gtk2_get_stock_icon(gint widget_type, const gchar *stock_id, - GtkIconSize size, GtkTextDirection direction, const char *detail); -GdkPixbuf *gtk2_get_icon(const gchar *filename, gint size); -jstring gtk2_get_pango_font_name(JNIEnv *env, WidgetType widget_type); - -void flush_gtk_event_loop(); - -jobject gtk2_get_setting(JNIEnv *env, Setting property); - -void gtk2_set_range_value(WidgetType widget_type, jdouble value, - jdouble min, jdouble max, jdouble visible); - -void (*fp_g_free)(gpointer mem); -void (*fp_g_object_unref)(gpointer object); -GdkWindow *(*fp_gdk_get_default_root_window) (void); - -int (*fp_gdk_pixbuf_get_bits_per_sample)(const GdkPixbuf *pixbuf); -guchar *(*fp_gdk_pixbuf_get_pixels)(const GdkPixbuf *pixbuf); -gboolean (*fp_gdk_pixbuf_get_has_alpha)(const GdkPixbuf *pixbuf); -int (*fp_gdk_pixbuf_get_height)(const GdkPixbuf *pixbuf); -int (*fp_gdk_pixbuf_get_n_channels)(const GdkPixbuf *pixbuf); -int (*fp_gdk_pixbuf_get_rowstride)(const GdkPixbuf *pixbuf); -int (*fp_gdk_pixbuf_get_width)(const GdkPixbuf *pixbuf); -GdkPixbuf *(*fp_gdk_pixbuf_new_from_file)(const char *filename, GError **error); -GdkColorspace (*fp_gdk_pixbuf_get_colorspace)(const GdkPixbuf *pixbuf); - -GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkPixbuf *dest, +static GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkPixbuf *dest, GdkDrawable *src, GdkColormap *cmap, int src_x, int src_y, int dest_x, int dest_y, int width, int height); -GdkPixbuf *(*fp_gdk_pixbuf_scale_simple)(GdkPixbuf *src, +static GdkPixbuf *(*fp_gdk_pixbuf_scale_simple)(GdkPixbuf *src, int dest_width, int dest_heigh, GdkInterpType interp_type); -void (*fp_gtk_widget_destroy)(GtkWidget *widget); -void (*fp_gtk_window_present)(GtkWindow *window); -void (*fp_gtk_window_move)(GtkWindow *window, gint x, gint y); -void (*fp_gtk_window_resize)(GtkWindow *window, gint width, gint height); +static void (*fp_gtk_widget_destroy)(void *widget); +static void (*fp_gtk_window_present)(GtkWindow *window); +static void (*fp_gtk_window_move)(GtkWindow *window, gint x, gint y); +static void (*fp_gtk_window_resize)(GtkWindow *window, gint width, gint height); /** * Function Pointers for GtkFileChooser */ -gchar* (*fp_gtk_file_chooser_get_filename)(GtkFileChooser *chooser); -void (*fp_gtk_widget_hide)(GtkWidget *widget); -void (*fp_gtk_main_quit)(void); -GtkWidget* (*fp_gtk_file_chooser_dialog_new)(const gchar *title, +static gchar* (*fp_gtk_file_chooser_get_filename)(GtkFileChooser *chooser); +static void (*fp_gtk_widget_hide)(void *widget); +static void (*fp_gtk_main_quit)(void); +static void* (*fp_gtk_file_chooser_dialog_new)(const gchar *title, GtkWindow *parent, GtkFileChooserAction action, const gchar *first_button_text, ...); -gboolean (*fp_gtk_file_chooser_set_current_folder)(GtkFileChooser *chooser, +static gboolean (*fp_gtk_file_chooser_set_current_folder)(GtkFileChooser *chooser, const gchar *filename); -gboolean (*fp_gtk_file_chooser_set_filename)(GtkFileChooser *chooser, +static gboolean (*fp_gtk_file_chooser_set_filename)(GtkFileChooser *chooser, const char *filename); -void (*fp_gtk_file_chooser_set_current_name)(GtkFileChooser *chooser, +static void (*fp_gtk_file_chooser_set_current_name)(GtkFileChooser *chooser, const gchar *name); -void (*fp_gtk_file_filter_add_custom)(GtkFileFilter *filter, +static void (*fp_gtk_file_filter_add_custom)(GtkFileFilter *filter, GtkFileFilterFlags needed, GtkFileFilterFunc func, gpointer data, GDestroyNotify notify); -void (*fp_gtk_file_chooser_set_filter)(GtkFileChooser *chooser, +static void (*fp_gtk_file_chooser_set_filter)(GtkFileChooser *chooser, GtkFileFilter *filter); -GType (*fp_gtk_file_chooser_get_type)(void); -GtkFileFilter* (*fp_gtk_file_filter_new)(void); -void (*fp_gtk_file_chooser_set_do_overwrite_confirmation)( +static GType (*fp_gtk_file_chooser_get_type)(void); +static GtkFileFilter* (*fp_gtk_file_filter_new)(void); +static void (*fp_gtk_file_chooser_set_do_overwrite_confirmation)( GtkFileChooser *chooser, gboolean do_overwrite_confirmation); -void (*fp_gtk_file_chooser_set_select_multiple)( +static void (*fp_gtk_file_chooser_set_select_multiple)( GtkFileChooser *chooser, gboolean select_multiple); -gchar* (*fp_gtk_file_chooser_get_current_folder)(GtkFileChooser *chooser); -GSList* (*fp_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser); -guint (*fp_gtk_g_slist_length)(GSList *list); -gulong (*fp_g_signal_connect_data)(gpointer instance, +static gchar* (*fp_gtk_file_chooser_get_current_folder)(GtkFileChooser *chooser); +static GSList* (*fp_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser); +static guint (*fp_gtk_g_slist_length)(GSList *list); +static gulong (*fp_g_signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags); -void (*fp_gtk_widget_show)(GtkWidget *widget); -void (*fp_gtk_main)(void); -guint (*fp_gtk_main_level)(void); -gchar* (*fp_g_path_get_dirname) (const gchar *file_name); -XID (*fp_gdk_x11_drawable_get_xid) (GdkWindow *drawable); +static void (*fp_gtk_widget_show)(void *widget); +static void (*fp_gtk_main)(void); +static guint (*fp_gtk_main_level)(void); +static gchar* (*fp_g_path_get_dirname) (const gchar *file_name); +static XID (*fp_gdk_x11_drawable_get_xid) (GdkWindow *drawable); - -GList* (*fp_g_list_append) (GList *list, gpointer data); -void (*fp_g_list_free) (GList *list); -void (*fp_g_list_free_full) (GList *list, GDestroyNotify free_func); +static GList* (*fp_g_list_append) (GList *list, gpointer data); +static void (*fp_g_list_free) (GList *list); +static void (*fp_g_list_free_full) (GList *list, GDestroyNotify free_func); /** * This function is available for GLIB > 2.20, so it MUST be * called within GLIB_CHECK_VERSION(2, 20, 0) check. */ -gboolean (*fp_g_thread_get_initialized)(void); +static gboolean (*fp_g_thread_get_initialized)(void); -void (*fp_g_thread_init)(GThreadFunctions *vtable); -void (*fp_gdk_threads_init)(void); -void (*fp_gdk_threads_enter)(void); -void (*fp_gdk_threads_leave)(void); +static void (*fp_g_thread_init)(GThreadFunctions *vtable); +static void (*fp_gdk_threads_init)(void); +static void (*fp_gdk_threads_enter)(void); +static void (*fp_gdk_threads_leave)(void); -gboolean (*fp_gtk_show_uri)(GdkScreen *screen, const gchar *uri, +static gboolean (*fp_gtk_show_uri)(GdkScreen *screen, const gchar *uri, guint32 timestamp, GError **error); #endif /* !_GTK2_INTERFACE_H */ diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c new file mode 100644 index 00000000000..385c8015046 --- /dev/null +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c @@ -0,0 +1,2881 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +#include +#include +#include +#include +#include +#include "gtk3_interface.h" +#include "java_awt_Transparency.h" +#include "sizecalc.h" +#include +#include +#include "awt.h" + +static void *gtk3_libhandle = NULL; + +static jmp_buf j; + +/* Widgets */ +static GtkWidget *gtk3_widget = NULL; +static GtkWidget *gtk3_window = NULL; +static GtkFixed *gtk3_fixed = NULL; +static GtkStyleProvider *gtk3_css = NULL; + +/* Paint system */ +static cairo_surface_t *surface = NULL; +static cairo_t *cr = NULL; + +static const char ENV_PREFIX[] = "GTK_MODULES="; + +static GtkWidget *gtk3_widgets[_GTK_WIDGET_TYPE_SIZE]; + +static void throw_exception(JNIEnv *env, const char* name, const char* message) +{ + jclass class = (*env)->FindClass(env, name); + + if (class != NULL) + (*env)->ThrowNew(env, class, message); + + (*env)->DeleteLocalRef(env, class); +} + +static void gtk3_add_state(GtkWidget *widget, GtkStateType state) { + GtkStateType old_state = fp_gtk_widget_get_state(widget); + fp_gtk_widget_set_state(widget, old_state | state); +} + +static void gtk3_remove_state(GtkWidget *widget, GtkStateType state) { + GtkStateType old_state = fp_gtk_widget_get_state(widget); + fp_gtk_widget_set_state(widget, old_state & ~state); +} + +/* This is a workaround for the bug: + * http://sourceware.org/bugzilla/show_bug.cgi?id=1814 + * (dlsym/dlopen clears dlerror state) + * This bug is specific to Linux, but there is no harm in + * applying this workaround on Solaris as well. + */ +static void* dl_symbol(const char* name) +{ + void* result = dlsym(gtk3_libhandle, name); + if (!result) + longjmp(j, NO_SYMBOL_EXCEPTION); + + return result; +} + +gboolean gtk3_check(const char* lib_name, int flags) +{ + if (gtk3_libhandle != NULL) { + /* We've already successfully opened the GTK libs, so return true. */ + return TRUE; + } else { + return dlopen(lib_name, flags) != NULL; + } +} + +#define ADD_SUPPORTED_ACTION(actionStr) \ +do { \ + jfieldID fld_action = (*env)->GetStaticFieldID(env, cls_action, actionStr, \ + "Ljava/awt/Desktop$Action;"); \ + if (!(*env)->ExceptionCheck(env)) { \ + jobject action = (*env)->GetStaticObjectField(env, cls_action, \ + fld_action); \ + (*env)->CallBooleanMethod(env, supportedActions, mid_arrayListAdd, \ + action); \ + } else { \ + (*env)->ExceptionClear(env); \ + } \ +} while(0); + + +static void update_supported_actions(JNIEnv *env) { + GVfs * (*fp_g_vfs_get_default) (void); + const gchar * const * (*fp_g_vfs_get_supported_uri_schemes) (GVfs * vfs); + const gchar * const * schemes = NULL; + + jclass cls_action = (*env)->FindClass(env, "java/awt/Desktop$Action"); + CHECK_NULL(cls_action); + jclass cls_xDesktopPeer = (*env)-> + FindClass(env, "sun/awt/X11/XDesktopPeer"); + CHECK_NULL(cls_xDesktopPeer); + jfieldID fld_supportedActions = (*env)->GetStaticFieldID(env, + cls_xDesktopPeer, "supportedActions", "Ljava/util/List;"); + CHECK_NULL(fld_supportedActions); + jobject supportedActions = (*env)->GetStaticObjectField(env, + cls_xDesktopPeer, fld_supportedActions); + + jclass cls_arrayList = (*env)->FindClass(env, "java/util/ArrayList"); + CHECK_NULL(cls_arrayList); + jmethodID mid_arrayListAdd = (*env)->GetMethodID(env, cls_arrayList, "add", + "(Ljava/lang/Object;)Z"); + CHECK_NULL(mid_arrayListAdd); + jmethodID mid_arrayListClear = (*env)->GetMethodID(env, cls_arrayList, + "clear", "()V"); + CHECK_NULL(mid_arrayListClear); + + (*env)->CallVoidMethod(env, supportedActions, mid_arrayListClear); + + ADD_SUPPORTED_ACTION("OPEN"); + + /** + * gtk_show_uri() documentation says: + * + * > you need to install gvfs to get support for uri schemes such as http:// + * > or ftp://, as only local files are handled by GIO itself. + * + * So OPEN action was safely added here. + * However, it looks like Solaris 11 have gvfs support only for 32-bit + * applications only by default. + */ + + fp_g_vfs_get_default = dl_symbol("g_vfs_get_default"); + fp_g_vfs_get_supported_uri_schemes = + dl_symbol("g_vfs_get_supported_uri_schemes"); + dlerror(); + + if (fp_g_vfs_get_default && fp_g_vfs_get_supported_uri_schemes) { + GVfs * vfs = fp_g_vfs_get_default(); + schemes = vfs ? fp_g_vfs_get_supported_uri_schemes(vfs) : NULL; + if (schemes) { + int i = 0; + while (schemes[i]) { + if (strcmp(schemes[i], "http") == 0) { + ADD_SUPPORTED_ACTION("BROWSE"); + ADD_SUPPORTED_ACTION("MAIL"); + break; + } + i++; + } + } + } else { +#ifdef DEBUG + fprintf(stderr, "Cannot load g_vfs_get_supported_uri_schemes\n"); +#endif /* DEBUG */ + } + +} +/** + * Functions for awt_Desktop.c + */ +static gboolean gtk3_show_uri_load(JNIEnv *env) { + gboolean success = FALSE; + dlerror(); + fp_gtk_show_uri = dl_symbol("gtk_show_uri"); + const char *dlsym_error = dlerror(); + if (dlsym_error) { +#ifdef DEBUG + fprintf (stderr, "Cannot load symbol: %s \n", dlsym_error); +#endif /* DEBUG */ + } else if (fp_gtk_show_uri == NULL) { +#ifdef DEBUG + fprintf(stderr, "dlsym(gtk_show_uri) returned NULL\n"); +#endif /* DEBUG */ + } else { + update_supported_actions(env); + success = TRUE; + } + return success; +} + +/** + * Functions for sun_awt_X11_GtkFileDialogPeer.c + */ +static void gtk3_file_chooser_load() +{ + fp_gtk_file_chooser_get_filename = dl_symbol( + "gtk_file_chooser_get_filename"); + fp_gtk_file_chooser_dialog_new = dl_symbol("gtk_file_chooser_dialog_new"); + fp_gtk_file_chooser_set_current_folder = dl_symbol( + "gtk_file_chooser_set_current_folder"); + fp_gtk_file_chooser_set_filename = dl_symbol( + "gtk_file_chooser_set_filename"); + fp_gtk_file_chooser_set_current_name = dl_symbol( + "gtk_file_chooser_set_current_name"); + fp_gtk_file_filter_add_custom = dl_symbol("gtk_file_filter_add_custom"); + fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter"); + fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type"); + fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new"); + fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol( + "gtk_file_chooser_set_do_overwrite_confirmation"); + fp_gtk_file_chooser_set_select_multiple = dl_symbol( + "gtk_file_chooser_set_select_multiple"); + fp_gtk_file_chooser_get_current_folder = dl_symbol( + "gtk_file_chooser_get_current_folder"); + fp_gtk_file_chooser_get_filenames = dl_symbol( + "gtk_file_chooser_get_filenames"); + fp_gtk_g_slist_length = dl_symbol("g_slist_length"); + fp_gdk_x11_drawable_get_xid = dl_symbol("gdk_x11_window_get_xid"); +} + +static void empty() {} + +static gboolean gtk3_version_3_10 = TRUE; +static gboolean gtk3_version_3_14 = FALSE; + +GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) +{ + gboolean result; + int i; + int (*handler)(); + int (*io_handler)(); + char *gtk_modules_env; + gtk3_libhandle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL); + if (gtk3_libhandle == NULL) { + return FALSE; + } + + if (setjmp(j) == 0) + { + fp_gtk_check_version = dl_symbol("gtk_check_version"); + + /* GLib */ + fp_glib_check_version = dlsym(gtk3_libhandle, "glib_check_version"); + if (!fp_glib_check_version) { + dlerror(); + } + fp_g_free = dl_symbol("g_free"); + fp_g_object_unref = dl_symbol("g_object_unref"); + + fp_g_main_context_iteration = + dl_symbol("g_main_context_iteration"); + + fp_g_value_init = dl_symbol("g_value_init"); + fp_g_type_is_a = dl_symbol("g_type_is_a"); + fp_g_value_get_boolean = dl_symbol("g_value_get_boolean"); + fp_g_value_get_char = dl_symbol("g_value_get_char"); + fp_g_value_get_uchar = dl_symbol("g_value_get_uchar"); + fp_g_value_get_int = dl_symbol("g_value_get_int"); + fp_g_value_get_uint = dl_symbol("g_value_get_uint"); + fp_g_value_get_long = dl_symbol("g_value_get_long"); + fp_g_value_get_ulong = dl_symbol("g_value_get_ulong"); + fp_g_value_get_int64 = dl_symbol("g_value_get_int64"); + fp_g_value_get_uint64 = dl_symbol("g_value_get_uint64"); + fp_g_value_get_float = dl_symbol("g_value_get_float"); + fp_g_value_get_double = dl_symbol("g_value_get_double"); + fp_g_value_get_string = dl_symbol("g_value_get_string"); + fp_g_value_get_enum = dl_symbol("g_value_get_enum"); + fp_g_value_get_flags = dl_symbol("g_value_get_flags"); + fp_g_value_get_param = dl_symbol("g_value_get_param"); + fp_g_value_get_boxed = dl_symbol("g_value_get_boxed"); + fp_g_value_get_pointer = dl_symbol("g_value_get_pointer"); + + fp_g_object_get = dl_symbol("g_object_get"); + fp_g_object_set = dl_symbol("g_object_set"); + + fp_g_str_has_prefix = dl_symbol("g_str_has_prefix"); + fp_g_strsplit = dl_symbol("g_strsplit"); + fp_g_strfreev = dl_symbol("g_strfreev"); + + /* GDK */ + fp_gdk_get_default_root_window = + dl_symbol("gdk_get_default_root_window"); + + /* Pixbuf */ + fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new"); + fp_gdk_pixbuf_new_from_file = + dl_symbol("gdk_pixbuf_new_from_file"); + fp_gdk_pixbuf_get_from_drawable = + dl_symbol("gdk_pixbuf_get_from_window"); + fp_gdk_pixbuf_get_width = dl_symbol("gdk_pixbuf_get_width"); + fp_gdk_pixbuf_get_height = dl_symbol("gdk_pixbuf_get_height"); + fp_gdk_pixbuf_get_pixels = dl_symbol("gdk_pixbuf_get_pixels"); + fp_gdk_pixbuf_get_rowstride = + dl_symbol("gdk_pixbuf_get_rowstride"); + fp_gdk_pixbuf_get_has_alpha = + dl_symbol("gdk_pixbuf_get_has_alpha"); + fp_gdk_pixbuf_get_bits_per_sample = + dl_symbol("gdk_pixbuf_get_bits_per_sample"); + fp_gdk_pixbuf_get_n_channels = + dl_symbol("gdk_pixbuf_get_n_channels"); + fp_gdk_pixbuf_get_colorspace = + dl_symbol("gdk_pixbuf_get_colorspace"); + + fp_cairo_image_surface_create = dl_symbol("cairo_image_surface_create"); + fp_cairo_surface_destroy = dl_symbol("cairo_surface_destroy"); + fp_cairo_create = dl_symbol("cairo_create"); + fp_cairo_destroy = dl_symbol("cairo_destroy"); + fp_cairo_fill = dl_symbol("cairo_fill"); + fp_cairo_rectangle = dl_symbol("cairo_rectangle"); + fp_cairo_set_source_rgb = dl_symbol("cairo_set_source_rgb"); + fp_cairo_set_source_rgba = dl_symbol("cairo_set_source_rgba"); + fp_cairo_surface_flush = dl_symbol("cairo_surface_flush"); + fp_cairo_paint = dl_symbol("cairo_paint"); + fp_cairo_clip = dl_symbol("cairo_clip"); + fp_cairo_image_surface_get_data = + dl_symbol("cairo_image_surface_get_data"); + fp_cairo_image_surface_get_stride = + dl_symbol("cairo_image_surface_get_stride"); + + fp_gdk_pixbuf_get_from_surface = + dl_symbol("gdk_pixbuf_get_from_surface"); + + fp_gtk_widget_get_state = dl_symbol("gtk_widget_get_state"); + fp_gtk_widget_set_state = dl_symbol("gtk_widget_set_state"); + + fp_gtk_widget_is_focus = dl_symbol("gtk_widget_is_focus"); + fp_gtk_widget_set_allocation = dl_symbol("gtk_widget_set_allocation"); + fp_gtk_widget_get_parent = dl_symbol("gtk_widget_get_parent"); + fp_gtk_widget_get_window = dl_symbol("gtk_widget_get_window"); + + fp_gtk_widget_get_style_context = + dl_symbol("gtk_widget_get_style_context"); + fp_gtk_style_context_get_color = + dl_symbol("gtk_style_context_get_color"); + fp_gtk_style_context_get_background_color = + dl_symbol("gtk_style_context_get_background_color"); + fp_gtk_widget_get_state_flags = dl_symbol("gtk_widget_get_state_flags"); + fp_gtk_style_context_set_state = + dl_symbol("gtk_style_context_set_state"); + fp_gtk_style_context_add_class = + dl_symbol("gtk_style_context_add_class"); + fp_gtk_style_context_save = dl_symbol("gtk_style_context_save"); + fp_gtk_style_context_restore = dl_symbol("gtk_style_context_restore"); + fp_gtk_render_check = dl_symbol("gtk_render_check"); + fp_gtk_render_option = dl_symbol("gtk_render_option"); + fp_gtk_render_extension = dl_symbol("gtk_render_extension"); + fp_gtk_render_expander = dl_symbol("gtk_render_expander"); + fp_gtk_render_frame_gap = dl_symbol("gtk_render_frame_gap"); + fp_gtk_render_line = dl_symbol("gtk_render_line"); + fp_gtk_widget_render_icon_pixbuf = + dl_symbol("gtk_widget_render_icon_pixbuf"); + if (fp_gtk_check_version(3, 10, 0)) { + gtk3_version_3_10 = FALSE; + } else { + fp_gdk_window_create_similar_image_surface = + dl_symbol("gdk_window_create_similar_image_surface"); + } + gtk3_version_3_14 = !fp_gtk_check_version(3, 14, 0); + + fp_gdk_window_create_similar_surface = + dl_symbol("gdk_window_create_similar_surface"); + fp_gtk_settings_get_for_screen = + dl_symbol("gtk_settings_get_for_screen"); + fp_gtk_widget_get_screen = dl_symbol("gtk_widget_get_screen"); + fp_gtk_css_provider_get_named = dl_symbol("gtk_css_provider_get_named"); + fp_gtk_style_context_add_provider = + dl_symbol("gtk_style_context_add_provider"); + fp_gtk_render_frame = dl_symbol("gtk_render_frame"); + fp_gtk_render_focus = dl_symbol("gtk_render_focus"); + fp_gtk_render_handle = dl_symbol("gtk_render_handle"); + fp_gtk_render_arrow = dl_symbol("gtk_render_arrow"); + + fp_gtk_style_context_get_property = + dl_symbol("gtk_style_context_get_property"); + fp_gtk_scrolled_window_set_shadow_type = + dl_symbol("gtk_scrolled_window_set_shadow_type"); + fp_gtk_render_slider = dl_symbol("gtk_render_slider"); + fp_gtk_style_context_get_padding = + dl_symbol("gtk_style_context_get_padding"); + fp_gtk_range_set_inverted = dl_symbol("gtk_range_set_inverted"); + fp_gtk_style_context_get_font = dl_symbol("gtk_style_context_get_font"); + fp_gtk_widget_get_allocated_width = + dl_symbol("gtk_widget_get_allocated_width"); + fp_gtk_widget_get_allocated_height = + dl_symbol("gtk_widget_get_allocated_height"); + fp_gtk_icon_theme_get_default = dl_symbol("gtk_icon_theme_get_default"); + fp_gtk_icon_theme_load_icon = dl_symbol("gtk_icon_theme_load_icon"); + + fp_gtk_adjustment_set_lower = dl_symbol("gtk_adjustment_set_lower"); + fp_gtk_adjustment_set_page_increment = + dl_symbol("gtk_adjustment_set_page_increment"); + fp_gtk_adjustment_set_page_size = + dl_symbol("gtk_adjustment_set_page_size"); + fp_gtk_adjustment_set_step_increment = + dl_symbol("gtk_adjustment_set_step_increment"); + fp_gtk_adjustment_set_upper = dl_symbol("gtk_adjustment_set_upper"); + fp_gtk_adjustment_set_value = dl_symbol("gtk_adjustment_set_value"); + + fp_gtk_render_activity = dl_symbol("gtk_render_activity"); + fp_gtk_render_background = dl_symbol("gtk_render_background"); + fp_gtk_style_context_has_class = + dl_symbol("gtk_style_context_has_class"); + + fp_gtk_style_context_set_junction_sides = + dl_symbol("gtk_style_context_set_junction_sides"); + fp_gtk_style_context_add_region = + dl_symbol("gtk_style_context_add_region"); + + fp_gtk_init_check = dl_symbol("gtk_init_check"); + + /* GTK widgets */ + fp_gtk_arrow_new = dl_symbol("gtk_arrow_new"); + fp_gtk_button_new = dl_symbol("gtk_button_new"); + fp_gtk_spin_button_new = dl_symbol("gtk_spin_button_new"); + fp_gtk_check_button_new = dl_symbol("gtk_check_button_new"); + fp_gtk_check_menu_item_new = + dl_symbol("gtk_check_menu_item_new"); + fp_gtk_color_selection_dialog_new = + dl_symbol("gtk_color_selection_dialog_new"); + fp_gtk_entry_new = dl_symbol("gtk_entry_new"); + fp_gtk_fixed_new = dl_symbol("gtk_fixed_new"); + fp_gtk_handle_box_new = dl_symbol("gtk_handle_box_new"); + fp_gtk_image_new = dl_symbol("gtk_image_new"); + fp_gtk_hpaned_new = dl_symbol("gtk_hpaned_new"); + fp_gtk_vpaned_new = dl_symbol("gtk_vpaned_new"); + fp_gtk_scale_new = dl_symbol("gtk_scale_new"); + fp_gtk_hscrollbar_new = dl_symbol("gtk_hscrollbar_new"); + fp_gtk_vscrollbar_new = dl_symbol("gtk_vscrollbar_new"); + fp_gtk_hseparator_new = dl_symbol("gtk_hseparator_new"); + fp_gtk_vseparator_new = dl_symbol("gtk_vseparator_new"); + fp_gtk_label_new = dl_symbol("gtk_label_new"); + fp_gtk_menu_new = dl_symbol("gtk_menu_new"); + fp_gtk_menu_bar_new = dl_symbol("gtk_menu_bar_new"); + fp_gtk_menu_item_new = dl_symbol("gtk_menu_item_new"); + fp_gtk_menu_item_set_submenu = + dl_symbol("gtk_menu_item_set_submenu"); + fp_gtk_notebook_new = dl_symbol("gtk_notebook_new"); + fp_gtk_progress_bar_new = + dl_symbol("gtk_progress_bar_new"); + fp_gtk_progress_bar_set_orientation = + dl_symbol("gtk_orientable_set_orientation"); + fp_gtk_radio_button_new = + dl_symbol("gtk_radio_button_new"); + fp_gtk_radio_menu_item_new = + dl_symbol("gtk_radio_menu_item_new"); + fp_gtk_scrolled_window_new = + dl_symbol("gtk_scrolled_window_new"); + fp_gtk_separator_menu_item_new = + dl_symbol("gtk_separator_menu_item_new"); + fp_gtk_text_view_new = dl_symbol("gtk_text_view_new"); + fp_gtk_toggle_button_new = + dl_symbol("gtk_toggle_button_new"); + fp_gtk_toolbar_new = dl_symbol("gtk_toolbar_new"); + fp_gtk_tree_view_new = dl_symbol("gtk_tree_view_new"); + fp_gtk_viewport_new = dl_symbol("gtk_viewport_new"); + fp_gtk_window_new = dl_symbol("gtk_window_new"); + fp_gtk_window_present = dl_symbol("gtk_window_present"); + fp_gtk_window_move = dl_symbol("gtk_window_move"); + fp_gtk_window_resize = dl_symbol("gtk_window_resize"); + + fp_gtk_dialog_new = dl_symbol("gtk_dialog_new"); + fp_gtk_frame_new = dl_symbol("gtk_frame_new"); + + fp_gtk_adjustment_new = dl_symbol("gtk_adjustment_new"); + fp_gtk_container_add = dl_symbol("gtk_container_add"); + fp_gtk_menu_shell_append = + dl_symbol("gtk_menu_shell_append"); + fp_gtk_widget_realize = dl_symbol("gtk_widget_realize"); + fp_gtk_widget_destroy = dl_symbol("gtk_widget_destroy"); + fp_gtk_widget_render_icon = + dl_symbol("gtk_widget_render_icon"); + fp_gtk_widget_set_name = + dl_symbol("gtk_widget_set_name"); + fp_gtk_widget_set_parent = + dl_symbol("gtk_widget_set_parent"); + fp_gtk_widget_set_direction = + dl_symbol("gtk_widget_set_direction"); + fp_gtk_widget_style_get = + dl_symbol("gtk_widget_style_get"); + fp_gtk_widget_class_install_style_property = + dl_symbol("gtk_widget_class_install_style_property"); + fp_gtk_widget_class_find_style_property = + dl_symbol("gtk_widget_class_find_style_property"); + fp_gtk_widget_style_get_property = + dl_symbol("gtk_widget_style_get_property"); + fp_pango_font_description_to_string = + dl_symbol("pango_font_description_to_string"); + fp_gtk_settings_get_default = + dl_symbol("gtk_settings_get_default"); + fp_gtk_widget_get_settings = + dl_symbol("gtk_widget_get_settings"); + fp_gtk_border_get_type = dl_symbol("gtk_border_get_type"); + fp_gtk_arrow_set = dl_symbol("gtk_arrow_set"); + fp_gtk_widget_size_request = + dl_symbol("gtk_widget_size_request"); + fp_gtk_range_get_adjustment = + dl_symbol("gtk_range_get_adjustment"); + + fp_gtk_widget_hide = dl_symbol("gtk_widget_hide"); + fp_gtk_main_quit = dl_symbol("gtk_main_quit"); + fp_g_signal_connect_data = dl_symbol("g_signal_connect_data"); + fp_gtk_widget_show = dl_symbol("gtk_widget_show"); + fp_gtk_main = dl_symbol("gtk_main"); + + fp_g_path_get_dirname = dl_symbol("g_path_get_dirname"); + + fp_gdk_threads_enter = ∅ + fp_gdk_threads_leave = ∅ + + /** + * Functions for sun_awt_X11_GtkFileDialogPeer.c + */ + gtk3_file_chooser_load(); + + fp_gtk_combo_box_new = dlsym(gtk3_libhandle, "gtk_combo_box_new"); + fp_gtk_combo_box_entry_new = dlsym(gtk3_libhandle, + "gtk_combo_box_new_with_entry"); + fp_gtk_separator_tool_item_new = dlsym(gtk3_libhandle, + "gtk_separator_tool_item_new"); + + fp_g_list_append = dl_symbol("g_list_append"); + fp_g_list_free = dl_symbol("g_list_free"); + fp_g_list_free_full = dl_symbol("g_list_free_full"); + } + /* Now we have only one kind of exceptions: NO_SYMBOL_EXCEPTION + * Otherwise we can check the return value of setjmp method. + */ + else + { + dlclose(gtk3_libhandle); + gtk3_libhandle = NULL; + + return NULL; + } + + /* + * Strip the AT-SPI GTK_MODULEs if present + */ + gtk_modules_env = getenv ("GTK_MODULES"); + if (gtk_modules_env && strstr (gtk_modules_env, "atk-bridge") || + gtk_modules_env && strstr (gtk_modules_env, "gail")) + { + /* the new env will be smaller than the old one */ + gchar *s, *new_env = SAFE_SIZE_STRUCT_ALLOC(malloc, + sizeof(ENV_PREFIX), 1, strlen (gtk_modules_env)); + + if (new_env != NULL ) + { + /* careful, strtok modifies its args */ + gchar *tmp_env = strdup (gtk_modules_env); + strcpy(new_env, ENV_PREFIX); + + /* strip out 'atk-bridge' and 'gail' */ + size_t PREFIX_LENGTH = strlen(ENV_PREFIX); + while (s = strtok(tmp_env, ":")) + { + if ((!strstr (s, "atk-bridge")) && (!strstr (s, "gail"))) + { + if (strlen (new_env) > PREFIX_LENGTH) { + new_env = strcat (new_env, ":"); + } + new_env = strcat(new_env, s); + } + if (tmp_env) + { + free (tmp_env); + tmp_env = NULL; /* next call to strtok arg1==NULL */ + } + } + putenv (new_env); + free (new_env); + free (tmp_env); + } + } + /* + * GTK should be initialized with gtk_init_check() before use. + * + * gtk_init_check installs its own error handlers. It is critical that + * we preserve error handler set from AWT. Otherwise we'll crash on + * BadMatch errors which we would normally ignore. The IO error handler + * is preserved here, too, just for consistency. + */ + AWT_LOCK(); + handler = XSetErrorHandler(NULL); + io_handler = XSetIOErrorHandler(NULL); + result = (*fp_gtk_init_check)(NULL, NULL); + XSetErrorHandler(handler); + XSetIOErrorHandler(io_handler); + AWT_UNLOCK(); + /* Initialize widget array. */ + for (i = 0; i < _GTK_WIDGET_TYPE_SIZE; i++) + { + gtk3_widgets[i] = NULL; + } + if (result) { + GtkApi* gtk = (GtkApi*)malloc(sizeof(GtkApi)); + gtk3_init(gtk); + return gtk; + } + return NULL; +} + +static int gtk3_unload() +{ + int i; + char *gtk3_error; + + if (!gtk3_libhandle) + return TRUE; + + /* Release painting objects */ + if (surface != NULL) { + fp_cairo_destroy(cr); + fp_cairo_surface_destroy(surface); + surface = NULL; + } + + if (gtk3_window != NULL) { + /* Destroying toplevel widget will destroy all contained widgets */ + (*fp_gtk_widget_destroy)(gtk3_window); + + /* Unset some static data so they get reinitialized on next load */ + gtk3_window = NULL; + } + + dlerror(); + dlclose(gtk3_libhandle); + if ((gtk3_error = dlerror()) != NULL) + { + return FALSE; + } + return TRUE; +} + +/* Dispatch all pending events from the GTK event loop. + * This is needed to catch theme change and update widgets' style. + */ +static void flush_gtk_event_loop() +{ + while((*fp_g_main_context_iteration)(NULL)); +} + +/* + * Initialize components of containment hierarchy. This creates a GtkFixed + * inside a GtkWindow. All widgets get realized. + */ +static void init_containers() +{ + if (gtk3_window == NULL) + { + gtk3_window = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL); + gtk3_fixed = (GtkFixed *)(*fp_gtk_fixed_new)(); + (*fp_gtk_container_add)((GtkContainer*)gtk3_window, + (GtkWidget *)gtk3_fixed); + (*fp_gtk_widget_realize)(gtk3_window); + (*fp_gtk_widget_realize)((GtkWidget *)gtk3_fixed); + + GtkSettings* settings = fp_gtk_settings_get_for_screen( + fp_gtk_widget_get_screen(gtk3_window)); + gchar* strval = NULL; + fp_g_object_get(settings, "gtk-theme-name", &strval, NULL); + gtk3_css = fp_gtk_css_provider_get_named(strval, NULL); + } +} + +/* + * Ensure everything is ready for drawing an element of the specified width + * and height. + * + * We should somehow handle translucent images. GTK can draw to X Drawables + * only, which don't support alpha. When we retrieve the image back from + * the server, translucency information is lost. There're several ways to + * work around this: + * 1) Subclass GdkPixmap and cache translucent objects on client side. This + * requires us to implement parts of X server drawing logic on client side. + * Many X requests can potentially be "translucent"; e.g. XDrawLine with + * fill=tile and a translucent tile is a "translucent" operation, whereas + * XDrawLine with fill=solid is an "opaque" one. Moreover themes can (and some + * do) intermix transparent and opaque operations which makes caching even + * more problematic. + * 2) Use Xorg 32bit ARGB visual when available. GDK has no native support + * for it (as of version 2.6). Also even in JDS 3 Xorg does not support + * these visuals by default, which makes optimizing for them pointless. + * We can consider doing this at a later point when ARGB visuals become more + * popular. + * 3') GTK has plans to use Cairo as its graphical backend (presumably in + * 2.8), and Cairo supports alpha. With it we could also get rid of the + * unnecessary round trip to server and do all the drawing on client side. + * 4) For now we draw to two different pixmaps and restore alpha channel by + * comparing results. This can be optimized by using subclassed pixmap and +*/ +static void gtk3_init_painting(JNIEnv *env, gint width, gint height) +{ + init_containers(); + + if (cr) { + fp_cairo_destroy(cr); + } + + if (surface != NULL) { + /* free old stuff */ + fp_cairo_surface_destroy(surface); + + } + + if (gtk3_version_3_10) { + surface = fp_gdk_window_create_similar_image_surface( + fp_gtk_widget_get_window(gtk3_window), + CAIRO_FORMAT_ARGB32, width, height, 1); + } else { + surface = fp_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + width, height); + } + + cr = fp_cairo_create(surface); +} + +/* + * Restore image from white and black pixmaps and copy it into destination + * buffer. This method compares two pixbufs taken from white and black + * pixmaps and decodes color and alpha components. Pixbufs are RGB without + * alpha, destination buffer is ABGR. + * + * The return value is the transparency type of the resulting image, either + * one of java_awt_Transparency_OPAQUE, java_awt_Transparency_BITMASK, and + * java_awt_Transparency_TRANSLUCENT. + */ +static gint gtk3_copy_image(gint *dst, gint width, gint height) +{ + gint i, j, r, g, b; + guchar *data; + gint stride, padding; + + fp_cairo_surface_flush(surface); + data = (*fp_cairo_image_surface_get_data)(surface); + stride = (*fp_cairo_image_surface_get_stride)(surface); + padding = stride - width * 4; + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + int r = *data++; + int g = *data++; + int b = *data++; + int a = *data++; + *dst++ = (a << 24 | b << 16 | g << 8 | r); + } + data += padding; + } + return java_awt_Transparency_TRANSLUCENT; +} + +static void gtk3_set_direction(GtkWidget *widget, GtkTextDirection dir) +{ + /* + * Some engines (inexplicably) look at the direction of the widget's + * parent, so we need to set the direction of both the widget and its + * parent. + */ + (*fp_gtk_widget_set_direction)(widget, dir); + GtkWidget* parent = fp_gtk_widget_get_parent(widget); + if (parent != NULL) { + fp_gtk_widget_set_direction(parent, dir); + } +} + +/* GTK state_type filter */ +static GtkStateType get_gtk_state_type(WidgetType widget_type, gint synth_state) +{ + GtkStateType result = GTK_STATE_NORMAL; + + if ((synth_state & DISABLED) != 0) { + result = GTK_STATE_INSENSITIVE; + } else if ((synth_state & PRESSED) != 0) { + result = GTK_STATE_ACTIVE; + } else if ((synth_state & MOUSE_OVER) != 0) { + result = GTK_STATE_PRELIGHT; + } + return result; +} + +static GtkStateFlags get_gtk_state_flags(gint synth_state) +{ + GtkStateFlags flags = 0; + + if ((synth_state & DISABLED) != 0) { + flags |= GTK_STATE_FLAG_INSENSITIVE; + } + if (((synth_state & PRESSED) != 0 || (synth_state & SELECTED) != 0)) { + flags |= GTK_STATE_FLAG_ACTIVE; + } + if ((synth_state & MOUSE_OVER) != 0) { + flags |= GTK_STATE_FLAG_PRELIGHT; + } + if ((synth_state & FOCUSED) != 0) { + flags |= GTK_STATE_FLAG_FOCUSED; + } + return flags; +} + +static GtkStateFlags get_gtk_flags(GtkStateType state_type) { + GtkStateFlags flags = 0; + switch (state_type) + { + case GTK_STATE_PRELIGHT: + flags |= GTK_STATE_FLAG_PRELIGHT; + break; + case GTK_STATE_SELECTED: + flags |= GTK_STATE_FLAG_SELECTED; + break; + case GTK_STATE_INSENSITIVE: + flags |= GTK_STATE_FLAG_INSENSITIVE; + break; + case GTK_STATE_ACTIVE: + flags |= GTK_STATE_FLAG_ACTIVE; + break; + case GTK_STATE_FOCUSED: + flags |= GTK_STATE_FLAG_FOCUSED; + break; + default: + break; + } + return flags; +} + +/* GTK shadow_type filter */ +static GtkShadowType get_gtk_shadow_type(WidgetType widget_type, + gint synth_state) +{ + GtkShadowType result = GTK_SHADOW_OUT; + + if ((synth_state & SELECTED) != 0) { + result = GTK_SHADOW_IN; + } + return result; +} + + +static GtkWidget* gtk3_get_arrow(GtkArrowType arrow_type, + GtkShadowType shadow_type) +{ + GtkWidget *arrow = NULL; + if (NULL == gtk3_widgets[_GTK_ARROW_TYPE]) + { + gtk3_widgets[_GTK_ARROW_TYPE] = (*fp_gtk_arrow_new)(arrow_type, + shadow_type); + (*fp_gtk_container_add)((GtkContainer *)gtk3_fixed, + gtk3_widgets[_GTK_ARROW_TYPE]); + (*fp_gtk_widget_realize)(gtk3_widgets[_GTK_ARROW_TYPE]); + } + arrow = gtk3_widgets[_GTK_ARROW_TYPE]; + + (*fp_gtk_arrow_set)(arrow, arrow_type, shadow_type); + return arrow; +} + +static GtkAdjustment* create_adjustment() +{ + return (GtkAdjustment *) + (*fp_gtk_adjustment_new)(50.0, 0.0, 100.0, 10.0, 20.0, 20.0); +} + +/** + * Returns a pointer to the cached native widget for the specified widget + * type. + */ +static GtkWidget *gtk3_get_widget(WidgetType widget_type) +{ + gboolean init_result = FALSE; + GtkWidget *result = NULL; + switch (widget_type) + { + case BUTTON: + case TABLE_HEADER: + if (init_result = (NULL == gtk3_widgets[_GTK_BUTTON_TYPE])) + { + gtk3_widgets[_GTK_BUTTON_TYPE] = (*fp_gtk_button_new)(); + } + result = gtk3_widgets[_GTK_BUTTON_TYPE]; + break; + case CHECK_BOX: + if (init_result = (NULL == gtk3_widgets[_GTK_CHECK_BUTTON_TYPE])) + { + gtk3_widgets[_GTK_CHECK_BUTTON_TYPE] = + (*fp_gtk_check_button_new)(); + } + result = gtk3_widgets[_GTK_CHECK_BUTTON_TYPE]; + break; + case CHECK_BOX_MENU_ITEM: + if (init_result = (NULL == gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE])) + { + gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE] = + (*fp_gtk_check_menu_item_new)(); + } + result = gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE]; + break; + /************************************************************ + * Creation a dedicated color chooser is dangerous because + * it deadlocks the EDT + ************************************************************/ +/* case COLOR_CHOOSER: + if (init_result = + (NULL == gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE])) + { + gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE] = + (*fp_gtk_color_selection_dialog_new)(NULL); + } + result = gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE]; + break;*/ + case COMBO_BOX: + if (init_result = (NULL == gtk3_widgets[_GTK_COMBO_BOX_TYPE])) + { + gtk3_widgets[_GTK_COMBO_BOX_TYPE] = + (*fp_gtk_combo_box_new)(); + } + result = gtk3_widgets[_GTK_COMBO_BOX_TYPE]; + break; + case COMBO_BOX_ARROW_BUTTON: + if (init_result = + (NULL == gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE])) + { + gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE] = + (*fp_gtk_toggle_button_new)(); + } + result = gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE]; + break; + case COMBO_BOX_TEXT_FIELD: + if (init_result = + (NULL == gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE])) + { + result = gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE] = + (*fp_gtk_entry_new)(); + } + result = gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE]; + break; + case DESKTOP_ICON: + case INTERNAL_FRAME_TITLE_PANE: + case LABEL: + if (init_result = (NULL == gtk3_widgets[_GTK_LABEL_TYPE])) + { + gtk3_widgets[_GTK_LABEL_TYPE] = + (*fp_gtk_label_new)(NULL); + } + result = gtk3_widgets[_GTK_LABEL_TYPE]; + break; + case DESKTOP_PANE: + case PANEL: + case ROOT_PANE: + if (init_result = (NULL == gtk3_widgets[_GTK_CONTAINER_TYPE])) + { + /* There is no constructor for a container type. I've + * chosen GtkFixed container since it has a default + * constructor. + */ + gtk3_widgets[_GTK_CONTAINER_TYPE] = + (*fp_gtk_fixed_new)(); + } + result = gtk3_widgets[_GTK_CONTAINER_TYPE]; + break; + case EDITOR_PANE: + case TEXT_AREA: + case TEXT_PANE: + if (init_result = (NULL == gtk3_widgets[_GTK_TEXT_VIEW_TYPE])) + { + gtk3_widgets[_GTK_TEXT_VIEW_TYPE] = + (*fp_gtk_text_view_new)(); + } + result = gtk3_widgets[_GTK_TEXT_VIEW_TYPE]; + break; + case FORMATTED_TEXT_FIELD: + case PASSWORD_FIELD: + case TEXT_FIELD: + if (init_result = (NULL == gtk3_widgets[_GTK_ENTRY_TYPE])) + { + gtk3_widgets[_GTK_ENTRY_TYPE] = + (*fp_gtk_entry_new)(); + } + result = gtk3_widgets[_GTK_ENTRY_TYPE]; + break; + case HANDLE_BOX: + if (init_result = (NULL == gtk3_widgets[_GTK_HANDLE_BOX_TYPE])) + { + gtk3_widgets[_GTK_HANDLE_BOX_TYPE] = + (*fp_gtk_handle_box_new)(); + } + result = gtk3_widgets[_GTK_HANDLE_BOX_TYPE]; + break; + case HSCROLL_BAR: + case HSCROLL_BAR_BUTTON_LEFT: + case HSCROLL_BAR_BUTTON_RIGHT: + case HSCROLL_BAR_TRACK: + case HSCROLL_BAR_THUMB: + if (init_result = (NULL == gtk3_widgets[_GTK_HSCROLLBAR_TYPE])) + { + gtk3_widgets[_GTK_HSCROLLBAR_TYPE] = + (*fp_gtk_hscrollbar_new)(create_adjustment()); + } + result = gtk3_widgets[_GTK_HSCROLLBAR_TYPE]; + break; + case HSEPARATOR: + if (init_result = (NULL == gtk3_widgets[_GTK_HSEPARATOR_TYPE])) + { + gtk3_widgets[_GTK_HSEPARATOR_TYPE] = + (*fp_gtk_hseparator_new)(); + } + result = gtk3_widgets[_GTK_HSEPARATOR_TYPE]; + break; + case HSLIDER: + case HSLIDER_THUMB: + case HSLIDER_TRACK: + if (init_result = (NULL == gtk3_widgets[_GTK_HSCALE_TYPE])) + { + gtk3_widgets[_GTK_HSCALE_TYPE] = + (*fp_gtk_scale_new)(GTK_ORIENTATION_HORIZONTAL, NULL); + } + result = gtk3_widgets[_GTK_HSCALE_TYPE]; + break; + case HSPLIT_PANE_DIVIDER: + case SPLIT_PANE: + if (init_result = (NULL == gtk3_widgets[_GTK_HPANED_TYPE])) + { + gtk3_widgets[_GTK_HPANED_TYPE] = (*fp_gtk_hpaned_new)(); + } + result = gtk3_widgets[_GTK_HPANED_TYPE]; + break; + case IMAGE: + if (init_result = (NULL == gtk3_widgets[_GTK_IMAGE_TYPE])) + { + gtk3_widgets[_GTK_IMAGE_TYPE] = (*fp_gtk_image_new)(); + } + result = gtk3_widgets[_GTK_IMAGE_TYPE]; + break; + case INTERNAL_FRAME: + if (init_result = (NULL == gtk3_widgets[_GTK_WINDOW_TYPE])) + { + gtk3_widgets[_GTK_WINDOW_TYPE] = + (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL); + } + result = gtk3_widgets[_GTK_WINDOW_TYPE]; + break; + case TOOL_TIP: + if (init_result = (NULL == gtk3_widgets[_GTK_TOOLTIP_TYPE])) + { + result = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL); + gtk3_widgets[_GTK_TOOLTIP_TYPE] = result; + } + result = gtk3_widgets[_GTK_TOOLTIP_TYPE]; + break; + case LIST: + case TABLE: + case TREE: + case TREE_CELL: + if (init_result = (NULL == gtk3_widgets[_GTK_TREE_VIEW_TYPE])) + { + gtk3_widgets[_GTK_TREE_VIEW_TYPE] = + (*fp_gtk_tree_view_new)(); + } + result = gtk3_widgets[_GTK_TREE_VIEW_TYPE]; + break; + case TITLED_BORDER: + if (init_result = (NULL == gtk3_widgets[_GTK_FRAME_TYPE])) + { + gtk3_widgets[_GTK_FRAME_TYPE] = fp_gtk_frame_new(NULL); + } + result = gtk3_widgets[_GTK_FRAME_TYPE]; + break; + case POPUP_MENU: + if (init_result = (NULL == gtk3_widgets[_GTK_MENU_TYPE])) + { + gtk3_widgets[_GTK_MENU_TYPE] = + (*fp_gtk_menu_new)(); + } + result = gtk3_widgets[_GTK_MENU_TYPE]; + break; + case MENU: + case MENU_ITEM: + case MENU_ITEM_ACCELERATOR: + if (init_result = (NULL == gtk3_widgets[_GTK_MENU_ITEM_TYPE])) + { + gtk3_widgets[_GTK_MENU_ITEM_TYPE] = + (*fp_gtk_menu_item_new)(); + } + result = gtk3_widgets[_GTK_MENU_ITEM_TYPE]; + break; + case MENU_BAR: + if (init_result = (NULL == gtk3_widgets[_GTK_MENU_BAR_TYPE])) + { + gtk3_widgets[_GTK_MENU_BAR_TYPE] = + (*fp_gtk_menu_bar_new)(); + } + result = gtk3_widgets[_GTK_MENU_BAR_TYPE]; + break; + case COLOR_CHOOSER: + case OPTION_PANE: + if (init_result = (NULL == gtk3_widgets[_GTK_DIALOG_TYPE])) + { + gtk3_widgets[_GTK_DIALOG_TYPE] = + (*fp_gtk_dialog_new)(); + } + result = gtk3_widgets[_GTK_DIALOG_TYPE]; + break; + case POPUP_MENU_SEPARATOR: + if (init_result = + (NULL == gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE])) + { + gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE] = + (*fp_gtk_separator_menu_item_new)(); + } + result = gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE]; + break; + case HPROGRESS_BAR: + if (init_result = (NULL == gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE])) + { + gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE] = + (*fp_gtk_progress_bar_new)(); + } + result = gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE]; + break; + case VPROGRESS_BAR: + if (init_result = (NULL == gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE])) + { + gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE] = + (*fp_gtk_progress_bar_new)(); + /* + * Vertical JProgressBars always go bottom-to-top, + * regardless of the ComponentOrientation. + */ + (*fp_gtk_progress_bar_set_orientation)( + (GtkProgressBar *)gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE], + GTK_PROGRESS_BOTTOM_TO_TOP); + } + result = gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE]; + break; + case RADIO_BUTTON: + if (init_result = (NULL == gtk3_widgets[_GTK_RADIO_BUTTON_TYPE])) + { + gtk3_widgets[_GTK_RADIO_BUTTON_TYPE] = + (*fp_gtk_radio_button_new)(NULL); + } + result = gtk3_widgets[_GTK_RADIO_BUTTON_TYPE]; + break; + case RADIO_BUTTON_MENU_ITEM: + if (init_result = + (NULL == gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE])) + { + gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE] = + (*fp_gtk_radio_menu_item_new)(NULL); + } + result = gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE]; + break; + case SCROLL_PANE: + if (init_result = + (NULL == gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE])) + { + gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE] = + (*fp_gtk_scrolled_window_new)(NULL, NULL); + } + result = gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE]; + break; + case SPINNER: + case SPINNER_ARROW_BUTTON: + case SPINNER_TEXT_FIELD: + if (init_result = (NULL == gtk3_widgets[_GTK_SPIN_BUTTON_TYPE])) + { + result = gtk3_widgets[_GTK_SPIN_BUTTON_TYPE] = + (*fp_gtk_spin_button_new)(NULL, 0, 0); + } + result = gtk3_widgets[_GTK_SPIN_BUTTON_TYPE]; + break; + case TABBED_PANE: + case TABBED_PANE_TAB_AREA: + case TABBED_PANE_CONTENT: + case TABBED_PANE_TAB: + if (init_result = (NULL == gtk3_widgets[_GTK_NOTEBOOK_TYPE])) + { + gtk3_widgets[_GTK_NOTEBOOK_TYPE] = + (*fp_gtk_notebook_new)(NULL); + } + result = gtk3_widgets[_GTK_NOTEBOOK_TYPE]; + break; + case TOGGLE_BUTTON: + if (init_result = (NULL == gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE])) + { + gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE] = + (*fp_gtk_toggle_button_new)(NULL); + } + result = gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE]; + break; + case TOOL_BAR: + case TOOL_BAR_DRAG_WINDOW: + if (init_result = (NULL == gtk3_widgets[_GTK_TOOLBAR_TYPE])) + { + gtk3_widgets[_GTK_TOOLBAR_TYPE] = + (*fp_gtk_toolbar_new)(NULL); + } + result = gtk3_widgets[_GTK_TOOLBAR_TYPE]; + break; + case TOOL_BAR_SEPARATOR: + if (init_result = + (NULL == gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE])) + { + gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE] = + (*fp_gtk_separator_tool_item_new)(); + } + result = gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE]; + break; + case VIEWPORT: + if (init_result = (NULL == gtk3_widgets[_GTK_VIEWPORT_TYPE])) + { + GtkAdjustment *adjustment = create_adjustment(); + gtk3_widgets[_GTK_VIEWPORT_TYPE] = + (*fp_gtk_viewport_new)(adjustment, adjustment); + } + result = gtk3_widgets[_GTK_VIEWPORT_TYPE]; + break; + case VSCROLL_BAR: + case VSCROLL_BAR_BUTTON_UP: + case VSCROLL_BAR_BUTTON_DOWN: + case VSCROLL_BAR_TRACK: + case VSCROLL_BAR_THUMB: + if (init_result = (NULL == gtk3_widgets[_GTK_VSCROLLBAR_TYPE])) + { + gtk3_widgets[_GTK_VSCROLLBAR_TYPE] = + (*fp_gtk_vscrollbar_new)(create_adjustment()); + } + result = gtk3_widgets[_GTK_VSCROLLBAR_TYPE]; + break; + case VSEPARATOR: + if (init_result = (NULL == gtk3_widgets[_GTK_VSEPARATOR_TYPE])) + { + gtk3_widgets[_GTK_VSEPARATOR_TYPE] = + (*fp_gtk_vseparator_new)(); + } + result = gtk3_widgets[_GTK_VSEPARATOR_TYPE]; + break; + case VSLIDER: + case VSLIDER_THUMB: + case VSLIDER_TRACK: + if (init_result = (NULL == gtk3_widgets[_GTK_VSCALE_TYPE])) + { + gtk3_widgets[_GTK_VSCALE_TYPE] = + (*fp_gtk_scale_new)(GTK_ORIENTATION_VERTICAL, NULL); + } + result = gtk3_widgets[_GTK_VSCALE_TYPE]; + /* + * Vertical JSliders start at the bottom, while vertical + * GtkVScale widgets start at the top (by default), so to fix + * this we set the "inverted" flag to get the Swing behavior. + */ + fp_gtk_range_set_inverted((GtkRange*)result, TRUE); + break; + case VSPLIT_PANE_DIVIDER: + if (init_result = (NULL == gtk3_widgets[_GTK_VPANED_TYPE])) + { + gtk3_widgets[_GTK_VPANED_TYPE] = (*fp_gtk_vpaned_new)(); + } + result = gtk3_widgets[_GTK_VPANED_TYPE]; + break; + default: + result = NULL; + break; + } + + if (result != NULL && init_result) + { + if (widget_type == RADIO_BUTTON_MENU_ITEM || + widget_type == CHECK_BOX_MENU_ITEM || + widget_type == MENU_ITEM || + widget_type == MENU || + widget_type == POPUP_MENU_SEPARATOR) + { + GtkWidget *menu = gtk3_get_widget(POPUP_MENU); + (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu, result); + } + else if (widget_type == POPUP_MENU) + { + GtkWidget *menu_bar = gtk3_get_widget(MENU_BAR); + GtkWidget *root_menu = (*fp_gtk_menu_item_new)(); + (*fp_gtk_menu_item_set_submenu)((GtkMenuItem*)root_menu, result); + (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu_bar, root_menu); + } + else if (widget_type == COMBO_BOX_TEXT_FIELD ) + { + GtkWidget* combo = gtk3_get_widget(COMBO_BOX); + + /* + * We add a regular GtkButton/GtkEntry to a GtkComboBoxEntry + * in order to trick engines into thinking it's a real combobox + * arrow button/text field. + */ + + fp_gtk_container_add ((GtkContainer*)(combo), result); + GtkStyleContext* context = fp_gtk_widget_get_style_context (combo); + fp_gtk_style_context_add_class (context, "combobox-entry"); + context = fp_gtk_widget_get_style_context (result); + fp_gtk_style_context_add_class (context, "combobox"); + fp_gtk_style_context_add_class (context, "entry"); + } + else if (widget_type == COMBO_BOX_ARROW_BUTTON ) + { + GtkWidget* combo = gtk3_get_widget(COMBO_BOX); + fp_gtk_widget_set_parent(result, combo); + } + else if (widget_type != TOOL_TIP && + widget_type != INTERNAL_FRAME && + widget_type != OPTION_PANE) + { + (*fp_gtk_container_add)((GtkContainer *)gtk3_fixed, result); + } + (*fp_gtk_widget_realize)(result); + } + return result; +} + +static void gtk3_paint_arrow(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, + GtkArrowType arrow_type, gboolean fill) +{ + gdouble xx, yy, a = G_PI; + int s = width; + gtk3_widget = gtk3_get_arrow(arrow_type, shadow_type); + + switch (widget_type) + { + case SPINNER_ARROW_BUTTON: + s = (int)(0.4 * width + 0.5) + 1; + if (arrow_type == GTK_ARROW_UP) { + a = 0; + } else if (arrow_type == GTK_ARROW_DOWN) { + a = G_PI; + } + break; + + case HSCROLL_BAR_BUTTON_LEFT: + s = (int)(0.5 * MIN(height, width * 2) + 0.5) + 1; + a = 3 * G_PI / 2; + break; + + case HSCROLL_BAR_BUTTON_RIGHT: + s = (int)(0.5 * MIN(height, width * 2) + 0.5) + 1; + a = G_PI / 2; + break; + + case VSCROLL_BAR_BUTTON_UP: + s = (int)(0.5 * MIN(height * 2, width) + 0.5) + 1; + a = 0; + break; + + case VSCROLL_BAR_BUTTON_DOWN: + s = (int)(0.5 * MIN(height * 2, width) + 0.5) + 1; + a = G_PI; + break; + + case COMBO_BOX_ARROW_BUTTON: + s = (int)(0.3 * height + 0.5) + 1; + a = G_PI; + break; + + case TABLE: + s = (int)(0.8 * height + 0.5) + 1; + if (arrow_type == GTK_ARROW_UP) { + a = G_PI; + } else if (arrow_type == GTK_ARROW_DOWN) { + a = 0; + } + break; + + case MENU_ITEM: + if (arrow_type == GTK_ARROW_UP) { + a = G_PI; + } else if (arrow_type == GTK_ARROW_DOWN) { + a = 0; + } else if (arrow_type == GTK_ARROW_RIGHT) { + a = G_PI / 2; + } else if (arrow_type == GTK_ARROW_LEFT) { + a = 3 * G_PI / 2; + } + break; + + default: + if (arrow_type == GTK_ARROW_UP) { + a = G_PI; + } else if (arrow_type == GTK_ARROW_DOWN) { + a = 0; + } else if (arrow_type == GTK_ARROW_RIGHT) { + a = G_PI / 2; + } else if (arrow_type == GTK_ARROW_LEFT) { + a = 3 * G_PI / 2; + } + break; + } + + if (s < width && s < height) { + xx = x + (0.5 * (width - s) + 0.5); + yy = y + (0.5 * (height - s) + 0.5); + } else { + xx = x; + yy = y; + } + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + fp_gtk_style_context_save (context); + + + if (detail != NULL) { + transform_detail_string(detail, context); + } + + GtkStateFlags flags = get_gtk_flags(state_type); + + fp_gtk_style_context_set_state (context, flags); + + (*fp_gtk_render_arrow)(context, cr, a, xx, yy, s); + + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_box(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, + gint synth_state, GtkTextDirection dir) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + if (widget_type == HSLIDER_TRACK) { + /* + * For horizontal JSliders with right-to-left orientation, we need + * to set the "inverted" flag to match the native GTK behavior where + * the foreground highlight is on the right side of the slider thumb. + * This is needed especially for the ubuntulooks engine, which looks + * exclusively at the "inverted" flag to determine on which side of + * the thumb to paint the highlight... + */ + fp_gtk_range_set_inverted((GtkRange*)gtk3_widget, dir == + GTK_TEXT_DIR_RTL); + + /* + * Note however that other engines like clearlooks will look at both + * the "inverted" field and the text direction to determine how + * the foreground highlight is painted: + * !inverted && ltr --> paint highlight on left side + * !inverted && rtl --> paint highlight on right side + * inverted && ltr --> paint highlight on right side + * inverted && rtl --> paint highlight on left side + * So the only way to reliably get the desired results for horizontal + * JSlider (i.e., highlight on left side for LTR ComponentOrientation + * and highlight on right side for RTL ComponentOrientation) is to + * always override text direction as LTR, and then set the "inverted" + * flag accordingly (as we have done above). + */ + dir = GTK_TEXT_DIR_LTR; + } + + /* + * Some engines (e.g. clearlooks) will paint the shadow of certain + * widgets (e.g. COMBO_BOX_ARROW_BUTTON) differently depending on the + * the text direction. + */ + gtk3_set_direction(gtk3_widget, dir); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + fp_gtk_style_context_save (context); + + transform_detail_string(detail, context); + + GtkStateFlags flags = get_gtk_flags(state_type); + + if (shadow_type == GTK_SHADOW_IN && widget_type != COMBO_BOX_ARROW_BUTTON) { + flags |= GTK_STATE_FLAG_ACTIVE; + } + + if (synth_state & MOUSE_OVER) { + flags |= GTK_STATE_FLAG_PRELIGHT; + } + + if (synth_state & FOCUSED) { + flags |= GTK_STATE_FLAG_FOCUSED; + } + + if (synth_state & DEFAULT) { + fp_gtk_style_context_add_class (context, "default"); + } + + fp_gtk_style_context_set_state (context, flags); + + if (fp_gtk_style_context_has_class(context, "progressbar")) { + fp_gtk_render_activity (context, cr, x, y, width, height); + } else { + fp_gtk_render_background (context, cr, x, y, width, height); + if (shadow_type != GTK_SHADOW_NONE) { + fp_gtk_render_frame(context, cr, x, y, width, height); + } + } + + fp_gtk_style_context_restore (context); + /* + * Reset the text direction to the default value so that we don't + * accidentally affect other operations and widgets. + */ + gtk3_set_direction(gtk3_widget, GTK_TEXT_DIR_LTR); +} + +static void gtk3_paint_box_gap(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, + GtkPositionType gap_side, gint gap_x, gint gap_width) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + GtkStateFlags flags = get_gtk_flags(state_type); + fp_gtk_style_context_set_state(context, flags); + + if (detail != 0) { + transform_detail_string(detail, context); + } + fp_gtk_render_background(context, cr, x, y, width, height); + + if (shadow_type != GTK_SHADOW_NONE) { + fp_gtk_render_frame_gap(context, cr, x, y, width, height, gap_side, + (gdouble)gap_x, (gdouble)gap_x + gap_width); + } + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_check(WidgetType widget_type, gint synth_state, + const gchar *detail, gint x, gint y, gint width, gint height) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + GtkStateFlags flags = get_gtk_state_flags(synth_state); + if (gtk3_version_3_14 && (synth_state & SELECTED)) { + flags = GTK_STATE_FLAG_CHECKED; + } + fp_gtk_style_context_set_state(context, flags); + + fp_gtk_style_context_add_class (context, "check"); + + fp_gtk_render_check (context, cr, x, y, width, height); + + fp_gtk_style_context_restore (context); +} + + +static void gtk3_paint_expander(WidgetType widget_type, GtkStateType state_type, + const gchar *detail, gint x, gint y, gint width, gint height, + GtkExpanderStyle expander_style) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + GtkStateFlags flags = get_gtk_flags(state_type); + fp_gtk_style_context_set_state(context, flags); + + if (detail != 0) { + transform_detail_string(detail, context); + } + + fp_gtk_render_expander (context, cr, x, y, width, height); + + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_extension(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, GtkPositionType gap_side) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + GtkStateFlags flags = GTK_STATE_FLAG_NORMAL; + + if (state_type == 0) { + flags = GTK_STATE_FLAG_ACTIVE; + } + + fp_gtk_style_context_set_state(context, flags); + + if (detail != 0) { + transform_detail_string(detail, context); + } + switch(gap_side) { + case GTK_POS_LEFT: + fp_gtk_style_context_add_class(context, "right"); + break; + case GTK_POS_RIGHT: + fp_gtk_style_context_add_class(context, "left"); + break; + case GTK_POS_TOP: + fp_gtk_style_context_add_class(context, "bottom"); + break; + case GTK_POS_BOTTOM: + fp_gtk_style_context_add_class(context, "top"); + break; + default: + break; + } + + fp_gtk_render_extension(context, cr, x, y, width, height, gap_side); + + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_flat_box(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, gboolean has_focus) +{ + if (state_type == GTK_STATE_PRELIGHT && + (widget_type == CHECK_BOX || widget_type == RADIO_BUTTON)) { + return; + } + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + if (detail != 0) { + transform_detail_string(detail, context); + } + + GtkStateFlags flags = get_gtk_flags(state_type); + + if (has_focus) { + flags |= GTK_STATE_FLAG_FOCUSED; + } + + fp_gtk_style_context_set_state (context, flags); + + if (widget_type == COMBO_BOX_TEXT_FIELD) { + width += height /2; + } + + fp_gtk_render_background (context, cr, x, y, width, height); + + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_focus(WidgetType widget_type, GtkStateType state_type, + const char *detail, gint x, gint y, gint width, gint height) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + fp_gtk_style_context_save (context); + + transform_detail_string(detail, context); + fp_gtk_render_focus (context, cr, x, y, width, height); + + fp_gtk_style_context_restore (context); + +} + +static void gtk3_paint_handle(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, GtkOrientation orientation) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + GtkStateFlags flags = get_gtk_flags(state_type); + fp_gtk_style_context_set_state(context, GTK_STATE_FLAG_PRELIGHT); + + if (detail != 0) { + transform_detail_string(detail, context); + fp_gtk_style_context_add_class (context, "handlebox_bin"); + } + + fp_gtk_render_handle(context, cr, x, y, width, height); + fp_gtk_render_background(context, cr, x, y, width, height); + + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_hline(WidgetType widget_type, GtkStateType state_type, + const gchar *detail, gint x, gint y, gint width, gint height) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + if (detail != 0) { + transform_detail_string(detail, context); + } + + fp_gtk_render_line(context, cr, x, y, x + width, y); + + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_vline(WidgetType widget_type, GtkStateType state_type, + const gchar *detail, gint x, gint y, gint width, gint height) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + if (detail != 0) { + transform_detail_string(detail, context); + } + + fp_gtk_render_line(context, cr, x, y, x, y + height); + + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_option(WidgetType widget_type, gint synth_state, + const gchar *detail, gint x, gint y, gint width, gint height) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + GtkStateFlags flags = get_gtk_state_flags(synth_state); + if (gtk3_version_3_14 && (synth_state & SELECTED)) { + flags = GTK_STATE_FLAG_CHECKED; + } + fp_gtk_style_context_set_state(context, flags); + + if (detail != 0) { + transform_detail_string(detail, context); + } + + fp_gtk_render_option(context, cr, x, y, width, height); + + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_shadow(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, + gint synth_state, GtkTextDirection dir) +{ + if (shadow_type == GTK_SHADOW_NONE) { + return; + } + gtk3_widget = gtk3_get_widget(widget_type); + + /* + * Some engines (e.g. clearlooks) will paint the shadow of certain + * widgets (e.g. COMBO_BOX_TEXT_FIELD) differently depending on the + * the text direction. + */ + gtk3_set_direction(gtk3_widget, dir); + + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + fp_gtk_style_context_save (context); + + if (detail) { + transform_detail_string(detail, context); + } + + GtkStateFlags flags = get_gtk_flags(state_type); + + if (synth_state & MOUSE_OVER) { + flags |= GTK_STATE_FLAG_PRELIGHT; + } + + if (synth_state & FOCUSED) { + flags |= GTK_STATE_FLAG_FOCUSED; + } + + fp_gtk_style_context_set_state (context, flags); + + if (widget_type == COMBO_BOX_TEXT_FIELD) { + width += height / 2; + } + fp_gtk_render_frame(context, cr, x, y, width, height); + + fp_gtk_style_context_restore (context); + + /* + * Reset the text direction to the default value so that we don't + * accidentally affect other operations and widgets. + */ + gtk3_set_direction(gtk3_widget, GTK_TEXT_DIR_LTR); +} + +static void gtk3_paint_slider(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, GtkOrientation orientation, + gboolean has_focus) +{ + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + + fp_gtk_style_context_save (context); + + if (detail) { + transform_detail_string(detail, context); + } + + GtkStateFlags flags = get_gtk_flags(state_type); + + if (state_type == GTK_STATE_ACTIVE) { + flags |= GTK_STATE_FLAG_PRELIGHT; + } + + if (has_focus) { + flags |= GTK_STATE_FLAG_FOCUSED; + } + + fp_gtk_style_context_set_state (context, flags); + + (*fp_gtk_render_slider)(context, cr, x, y, width, height, orientation); + + fp_gtk_style_context_restore (context); +} + +static void gtk3_paint_background(WidgetType widget_type, + GtkStateType state_type, gint x, gint y, gint width, gint height) { + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + fp_gtk_style_context_save (context); + + GtkStateFlags flags = get_gtk_flags(state_type); + + fp_gtk_style_context_set_state (context, flags); + + fp_gtk_render_background (context, cr, x, y, width, height); + + fp_gtk_style_context_restore (context); +} + +static GdkPixbuf *gtk3_get_stock_icon(gint widget_type, const gchar *stock_id, + GtkIconSize size, GtkTextDirection direction, const char *detail) +{ + int sz; + + switch(size) { + case GTK_ICON_SIZE_MENU: + sz = 16; + break; + case GTK_ICON_SIZE_SMALL_TOOLBAR: + sz = 18; + break; + case GTK_ICON_SIZE_LARGE_TOOLBAR: + sz = 24; + break; + case GTK_ICON_SIZE_BUTTON: + sz = 20; + break; + case GTK_ICON_SIZE_DND: + sz = 32; + break; + case GTK_ICON_SIZE_DIALOG: + sz = 48; + break; + default: + sz = 0; + break; + } + + init_containers(); + gtk3_widget = gtk3_get_widget((widget_type < 0) ? IMAGE : widget_type); + (*fp_gtk_widget_set_direction)(gtk3_widget, direction); + GtkIconTheme *icon_theme = fp_gtk_icon_theme_get_default(); + GdkPixbuf *result = fp_gtk_icon_theme_load_icon(icon_theme, stock_id, sz, + GTK_ICON_LOOKUP_USE_BUILTIN, NULL); + return result; +} + +static jboolean gtk3_get_pixbuf_data(JNIEnv *env, GdkPixbuf* pixbuf, + jmethodID icon_upcall_method, jobject this) { + if (!pixbuf) { + return JNI_FALSE; + } + guchar *pixbuf_data = (*fp_gdk_pixbuf_get_pixels)(pixbuf); + if (pixbuf_data) { + int row_stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); + int width = (*fp_gdk_pixbuf_get_width)(pixbuf); + int height = (*fp_gdk_pixbuf_get_height)(pixbuf); + int bps = (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf); + int channels = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); + gboolean alpha = (*fp_gdk_pixbuf_get_has_alpha)(pixbuf); + + jbyteArray data = (*env)->NewByteArray(env, (row_stride * height)); + JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); + + (*env)->SetByteArrayRegion(env, data, 0, (row_stride * height), + (jbyte *)pixbuf_data); + (*fp_g_object_unref)(pixbuf); + + /* Call the callback method to create the image on the Java side. */ + (*env)->CallVoidMethod(env, this, icon_upcall_method, data, + width, height, row_stride, bps, channels, alpha); + return JNI_TRUE; + } + return JNI_FALSE; +} + +static jboolean gtk3_get_file_icon_data(JNIEnv *env, const char *filename, + GError **error, jmethodID icon_upcall_method, jobject this) { + GdkPixbuf* pixbuf = fp_gdk_pixbuf_new_from_file(filename, error); + return gtk3_get_pixbuf_data(env, pixbuf, icon_upcall_method, this); +} + +static jboolean gtk3_get_icon_data(JNIEnv *env, gint widget_type, + const gchar *stock_id, GtkIconSize size, + GtkTextDirection direction, const char *detail, + jmethodID icon_upcall_method, jobject this) { + GdkPixbuf* pixbuf = gtk3_get_stock_icon(widget_type, stock_id, size, + direction, detail); + return gtk3_get_pixbuf_data(env, pixbuf, icon_upcall_method, this); +} + +/*************************************************/ +static gint gtk3_get_xthickness(JNIEnv *env, WidgetType widget_type) +{ + init_containers(); + + gtk3_widget = gtk3_get_widget(widget_type); + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + if (context) { + GtkBorder padding; + fp_gtk_style_context_get_padding(context, 0, &padding); + return padding.left + 1; + } + return 0; +} + +static gint gtk3_get_ythickness(JNIEnv *env, WidgetType widget_type) +{ + init_containers(); + + gtk3_widget = gtk3_get_widget(widget_type); + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + if (context) { + GtkBorder padding; + fp_gtk_style_context_get_padding(context, 0, &padding); + return padding.top + 1; + } + return 0; +} + +/*************************************************/ +static guint8 recode_color(gdouble channel) +{ + guint16 result = (guint16)(channel * 65535); + if (result < 0) { + result = 0; + } else if (result > 65535) { + result = 65535; + } + return (guint8)( result >> 8); +} + +static GtkStateFlags gtk3_get_state_flags(GtkStateType state_type) { + switch (state_type) + { + case GTK_STATE_NORMAL: + return GTK_STATE_FLAG_NORMAL; + case GTK_STATE_ACTIVE: + return GTK_STATE_FLAG_ACTIVE; + case GTK_STATE_PRELIGHT: + return GTK_STATE_FLAG_PRELIGHT; + case GTK_STATE_SELECTED: + return GTK_STATE_FLAG_SELECTED; + case GTK_STATE_INSENSITIVE: + return GTK_STATE_FLAG_INSENSITIVE; + case GTK_STATE_INCONSISTENT: + return GTK_STATE_FLAG_INCONSISTENT; + case GTK_STATE_FOCUSED: + return GTK_STATE_FLAG_FOCUSED; + } + return 0; +} + + +static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b) { + gdouble min; + gdouble max; + gdouble red; + gdouble green; + gdouble blue; + gdouble h, l, s; + gdouble delta; + + red = *r; + green = *g; + blue = *b; + + if (red > green) + { + if (red > blue) + max = red; + else + max = blue; + + if (green < blue) + min = green; + else + min = blue; + } + else + { + if (green > blue) + max = green; + else + max = blue; + + if (red < blue) + min = red; + else + min = blue; + } + + l = (max + min) / 2; + s = 0; + h = 0; + + if (max != min) + { + if (l <= 0.5) + s = (max - min) / (max + min); + else + s = (max - min) / (2 - max - min); + + delta = max -min; + if (red == max) + h = (green - blue) / delta; + else if (green == max) + h = 2 + (blue - red) / delta; + else if (blue == max) + h = 4 + (red - green) / delta; + + h *= 60; + if (h < 0.0) + h += 360; + } + + *r = h; + *g = l; + *b = s; +} + +static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s) +{ + gdouble hue; + gdouble lightness; + gdouble saturation; + gdouble m1, m2; + gdouble r, g, b; + + lightness = *l; + saturation = *s; + + if (lightness <= 0.5) + m2 = lightness * (1 + saturation); + else + m2 = lightness + saturation - lightness * saturation; + m1 = 2 * lightness - m2; + + if (saturation == 0) + { + *h = lightness; + *l = lightness; + *s = lightness; + } + else + { + hue = *h + 120; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + r = m1 + (m2 - m1) * hue / 60; + else if (hue < 180) + r = m2; + else if (hue < 240) + r = m1 + (m2 - m1) * (240 - hue) / 60; + else + r = m1; + + hue = *h; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + g = m1 + (m2 - m1) * hue / 60; + else if (hue < 180) + g = m2; + else if (hue < 240) + g = m1 + (m2 - m1) * (240 - hue) / 60; + else + g = m1; + + hue = *h - 120; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + b = m1 + (m2 - m1) * hue / 60; + else if (hue < 180) + b = m2; + else if (hue < 240) + b = m1 + (m2 - m1) * (240 - hue) / 60; + else + b = m1; + + *h = r; + *l = g; + *s = b; + } +} + + + +static void gtk3_style_shade (const GdkRGBA *a, GdkRGBA *b, gdouble k) { + gdouble red = a->red; + gdouble green = a->green; + gdouble blue = a->blue; + + rgb_to_hls (&red, &green, &blue); + + green *= k; + if (green > 1.0) + green = 1.0; + else if (green < 0.0) + green = 0.0; + + blue *= k; + if (blue > 1.0) + blue = 1.0; + else if (blue < 0.0) + blue = 0.0; + + hls_to_rgb (&red, &green, &blue); + + b->red = red; + b->green = green; + b->blue = blue; +} + +static GdkRGBA gtk3_get_color_for_flags(GtkStyleContext* context, + GtkStateFlags flags, ColorType color_type) { + GdkRGBA c, color; + + switch (color_type) + { + case FOREGROUND: + case TEXT_FOREGROUND: + fp_gtk_style_context_get_color(context, flags, &color); + break; + case BACKGROUND: + case TEXT_BACKGROUND: + fp_gtk_style_context_get_background_color(context, flags, &color); + break; + case LIGHT: + c = gtk3_get_color_for_flags(context, flags, BACKGROUND); + gtk3_style_shade(&c, &color, LIGHTNESS_MULT); + break; + case DARK: + c = gtk3_get_color_for_flags(context, flags, BACKGROUND); + gtk3_style_shade (&c, &color, DARKNESS_MULT); + break; + case MID: + { + GdkRGBA c1 = gtk3_get_color_for_flags(context, flags, LIGHT); + GdkRGBA c2 = gtk3_get_color_for_flags(context, flags, DARK); + color.red = (c1.red + c2.red) / 2; + color.green = (c1.green + c2.green) / 2; + color.blue = (c1.blue + c2.blue) / 2; + } + break; + case FOCUS: + case BLACK: + color.red = 0; + color.green = 0; + color.blue = 0; + break; + case WHITE: + color.red = 1; + color.green = 1; + color.blue = 1; + break; + } + return color; +} + +static gint gtk3_get_color_for_state(JNIEnv *env, WidgetType widget_type, + GtkStateType state_type, ColorType color_type) +{ + + gint result = 0; + GdkRGBA color; + + GtkStateFlags flags = gtk3_get_state_flags(state_type); + + init_containers(); + + gtk3_widget = gtk3_get_widget(widget_type); + + GtkStyleContext* context = fp_gtk_widget_get_style_context(gtk3_widget); + + if (widget_type == TOOL_TIP) { + fp_gtk_style_context_add_class(context, "tooltip"); + } + if (widget_type == CHECK_BOX_MENU_ITEM + || widget_type == RADIO_BUTTON_MENU_ITEM) { + flags &= GTK_STATE_FLAG_NORMAL | GTK_STATE_FLAG_SELECTED + | GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_FOCUSED; + } + + color = gtk3_get_color_for_flags(context, flags, color_type); + + if (recode_color(color.alpha) == 0) { + color = gtk3_get_color_for_flags( + fp_gtk_widget_get_style_context(gtk3_get_widget(INTERNAL_FRAME)), + 0, BACKGROUND); + } + + result = recode_color(color.alpha) << 24 | recode_color(color.red) << 16 | + recode_color(color.green) << 8 | recode_color(color.blue); + + return result; +} + +/*************************************************/ +static jobject create_Boolean(JNIEnv *env, jboolean boolean_value); +static jobject create_Integer(JNIEnv *env, jint int_value); +static jobject create_Long(JNIEnv *env, jlong long_value); +static jobject create_Float(JNIEnv *env, jfloat float_value); +static jobject create_Double(JNIEnv *env, jdouble double_value); +static jobject create_Character(JNIEnv *env, jchar char_value); +static jobject create_Insets(JNIEnv *env, GtkBorder *border); + +static jobject gtk3_get_class_value(JNIEnv *env, WidgetType widget_type, + const char* key) +{ + init_containers(); + + gtk3_widget = gtk3_get_widget(widget_type); + + GValue value = { 0, { { 0 } } }; + + GParamSpec* param = (*fp_gtk_widget_class_find_style_property)( + ((GTypeInstance*)gtk3_widget)->g_class, key); + if ( param ) + { + (*fp_g_value_init)( &value, param->value_type ); + (*fp_gtk_widget_style_get_property)(gtk3_widget, key, &value); + + if ((*fp_g_type_is_a)( param->value_type, G_TYPE_BOOLEAN )) + { + gboolean val = (*fp_g_value_get_boolean)(&value); + return create_Boolean(env, (jboolean)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_CHAR )) + { + gchar val = (*fp_g_value_get_char)(&value); + return create_Character(env, (jchar)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UCHAR )) + { + guchar val = (*fp_g_value_get_uchar)(&value); + return create_Character(env, (jchar)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_INT )) + { + gint val = (*fp_g_value_get_int)(&value); + return create_Integer(env, (jint)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UINT )) + { + guint val = (*fp_g_value_get_uint)(&value); + return create_Integer(env, (jint)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_LONG )) + { + glong val = (*fp_g_value_get_long)(&value); + return create_Long(env, (jlong)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_ULONG )) + { + gulong val = (*fp_g_value_get_ulong)(&value); + return create_Long(env, (jlong)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_INT64 )) + { + gint64 val = (*fp_g_value_get_int64)(&value); + return create_Long(env, (jlong)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UINT64 )) + { + guint64 val = (*fp_g_value_get_uint64)(&value); + return create_Long(env, (jlong)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_FLOAT )) + { + gfloat val = (*fp_g_value_get_float)(&value); + return create_Float(env, (jfloat)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_DOUBLE )) + { + gdouble val = (*fp_g_value_get_double)(&value); + return create_Double(env, (jdouble)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_ENUM )) + { + gint val = (*fp_g_value_get_enum)(&value); + return create_Integer(env, (jint)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_FLAGS )) + { + guint val = (*fp_g_value_get_flags)(&value); + return create_Integer(env, (jint)val); + } + else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_STRING )) + { + const gchar* val = (*fp_g_value_get_string)(&value); + + /* We suppose that all values come in C locale and + * utf-8 representation of a string is the same as + * the string itself. If this isn't so we should + * use g_convert. + */ + return (*env)->NewStringUTF(env, val); + } + else if ((*fp_g_type_is_a)( param->value_type, GTK_TYPE_BORDER )) + { + GtkBorder *border = (GtkBorder*)(*fp_g_value_get_boxed)(&value); + return border ? create_Insets(env, border) : NULL; + } + + /* TODO: Other types are not supported yet.*/ +/* else if((*fp_g_type_is_a)( param->value_type, G_TYPE_PARAM )) + { + GParamSpec* val = (*fp_g_value_get_param)(&value); + printf( "Param: %p\n", val ); + } + else if((*fp_g_type_is_a)( param->value_type, G_TYPE_BOXED )) + { + gpointer* val = (*fp_g_value_get_boxed)(&value); + printf( "Boxed: %p\n", val ); + } + else if((*fp_g_type_is_a)( param->value_type, G_TYPE_POINTER )) + { + gpointer* val = (*fp_g_value_get_pointer)(&value); + printf( "Pointer: %p\n", val ); + } + else if((*fp_g_type_is_a)( param->value_type, G_TYPE_OBJECT )) + { + GObject* val = (GObject*)(*fp_g_value_get_object)(&value); + printf( "Object: %p\n", val ); + }*/ + } + + return NULL; +} + +static void gtk3_set_range_value(WidgetType widget_type, jdouble value, + jdouble min, jdouble max, jdouble visible) +{ + GtkAdjustment *adj; + + gtk3_widget = gtk3_get_widget(widget_type); + + adj = (*fp_gtk_range_get_adjustment)((GtkRange *)gtk3_widget); + + fp_gtk_adjustment_set_value(adj, value); + fp_gtk_adjustment_set_lower(adj, min); + fp_gtk_adjustment_set_upper(adj, max); + fp_gtk_adjustment_set_page_size(adj, visible); +} + +/*************************************************/ +static jobject create_Object(JNIEnv *env, jmethodID *cid, + const char* class_name, + const char* signature, + jvalue* value) +{ + jclass class; + jobject result; + + class = (*env)->FindClass(env, class_name); + if (class == NULL) + return NULL; /* can't find/load the class, exception thrown */ + + if (*cid == NULL) + { + *cid = (*env)->GetMethodID(env, class, "", signature); + if (*cid == NULL) + { + (*env)->DeleteLocalRef(env, class); + return NULL; /* can't find/get the method, exception thrown */ + } + } + + result = (*env)->NewObjectA(env, class, *cid, value); + + (*env)->DeleteLocalRef(env, class); + return result; +} + +jobject create_Boolean(JNIEnv *env, jboolean boolean_value) +{ + static jmethodID cid = NULL; + jvalue value; + + value.z = boolean_value; + + return create_Object(env, &cid, "java/lang/Boolean", "(Z)V", &value); +} + +jobject create_Integer(JNIEnv *env, jint int_value) +{ + static jmethodID cid = NULL; + jvalue value; + + value.i = int_value; + + return create_Object(env, &cid, "java/lang/Integer", "(I)V", &value); +} + +jobject create_Long(JNIEnv *env, jlong long_value) +{ + static jmethodID cid = NULL; + jvalue value; + + value.j = long_value; + + return create_Object(env, &cid, "java/lang/Long", "(J)V", &value); +} + +jobject create_Float(JNIEnv *env, jfloat float_value) +{ + static jmethodID cid = NULL; + jvalue value; + + value.f = float_value; + + return create_Object(env, &cid, "java/lang/Float", "(F)V", &value); +} + +jobject create_Double(JNIEnv *env, jdouble double_value) +{ + static jmethodID cid = NULL; + jvalue value; + + value.d = double_value; + + return create_Object(env, &cid, "java/lang/Double", "(D)V", &value); +} + +jobject create_Character(JNIEnv *env, jchar char_value) +{ + static jmethodID cid = NULL; + jvalue value; + + value.c = char_value; + + return create_Object(env, &cid, "java/lang/Character", "(C)V", &value); +} + + +jobject create_Insets(JNIEnv *env, GtkBorder *border) +{ + static jmethodID cid = NULL; + jvalue values[4]; + + values[0].i = border->top; + values[1].i = border->left; + values[2].i = border->bottom; + values[3].i = border->right; + + return create_Object(env, &cid, "java/awt/Insets", "(IIII)V", values); +} + +/*********************************************/ +static jstring gtk3_get_pango_font_name(JNIEnv *env, WidgetType widget_type) +{ + init_containers(); + + gtk3_widget = gtk3_get_widget(widget_type); + jstring result = NULL; + GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget); + if (context) + { + PangoFontDescription* fd = fp_gtk_style_context_get_font(context, 0); + gchar* val = (*fp_pango_font_description_to_string)(fd); + result = (*env)->NewStringUTF(env, val); + (*fp_g_free)( val ); + } + + return result; +} + +/***********************************************/ +static jobject get_string_property(JNIEnv *env, GtkSettings* settings, + const gchar* key) { + jobject result = NULL; + gchar* strval = NULL; + + (*fp_g_object_get)(settings, key, &strval, NULL); + result = (*env)->NewStringUTF(env, strval); + (*fp_g_free)(strval); + + return result; +} + +static jobject get_integer_property(JNIEnv *env, GtkSettings* settings, + const gchar* key) { + gint intval = NULL; + (*fp_g_object_get)(settings, key, &intval, NULL); + return create_Integer(env, intval); +} + +static jobject get_boolean_property(JNIEnv *env, GtkSettings* settings, + const gchar* key) { + gint intval = NULL; + (*fp_g_object_get)(settings, key, &intval, NULL); + return create_Boolean(env, intval); +} + +static jobject gtk3_get_setting(JNIEnv *env, Setting property) +{ + GtkSettings* settings = (*fp_gtk_settings_get_default)(); + + switch (property) + { + case GTK_FONT_NAME: + return get_string_property(env, settings, "gtk-font-name"); + case GTK_ICON_SIZES: + return get_string_property(env, settings, "gtk-icon-sizes"); + case GTK_CURSOR_BLINK: + return get_boolean_property(env, settings, "gtk-cursor-blink"); + case GTK_CURSOR_BLINK_TIME: + return get_integer_property(env, settings, "gtk-cursor-blink-time"); + } + + return NULL; +} + +static void transform_detail_string (const gchar *detail, + GtkStyleContext *context) { + if (!detail) + return; + + if (strcmp (detail, "arrow") == 0) + fp_gtk_style_context_add_class (context, "arrow"); + else if (strcmp (detail, "button") == 0) + fp_gtk_style_context_add_class (context, "button"); + else if (strcmp (detail, "buttondefault") == 0) + { + fp_gtk_style_context_add_class (context, "button"); + fp_gtk_style_context_add_class (context, "default"); + } + else if (strcmp (detail, "calendar") == 0) + fp_gtk_style_context_add_class (context, "calendar"); + else if (strcmp (detail, "cellcheck") == 0) + { + fp_gtk_style_context_add_class (context, "cell"); + fp_gtk_style_context_add_class (context, "check"); + } + else if (strcmp (detail, "cellradio") == 0) + { + fp_gtk_style_context_add_class (context, "cell"); + fp_gtk_style_context_add_class (context, "radio"); + } + else if (strcmp (detail, "checkbutton") == 0) + fp_gtk_style_context_add_class (context, "check"); + else if (strcmp (detail, "check") == 0) + { + fp_gtk_style_context_add_class (context, "check"); + fp_gtk_style_context_add_class (context, "menu"); + } + else if (strcmp (detail, "radiobutton") == 0) + { + fp_gtk_style_context_add_class (context, "radio"); + } + else if (strcmp (detail, "option") == 0) + { + fp_gtk_style_context_add_class (context, "radio"); + fp_gtk_style_context_add_class (context, "menu"); + } + else if (strcmp (detail, "entry") == 0 || + strcmp (detail, "entry_bg") == 0) + fp_gtk_style_context_add_class (context, "entry"); + else if (strcmp (detail, "expander") == 0) + fp_gtk_style_context_add_class (context, "expander"); + else if (strcmp (detail, "tooltip") == 0) + fp_gtk_style_context_add_class (context, "tooltip"); + else if (strcmp (detail, "frame") == 0) + fp_gtk_style_context_add_class (context, "frame"); + else if (strcmp (detail, "scrolled_window") == 0) + fp_gtk_style_context_add_class (context, "scrolled-window"); + else if (strcmp (detail, "viewport") == 0 || + strcmp (detail, "viewportbin") == 0) + fp_gtk_style_context_add_class (context, "viewport"); + else if (strncmp (detail, "trough", 6) == 0) + fp_gtk_style_context_add_class (context, "trough"); + else if (strcmp (detail, "spinbutton") == 0) + fp_gtk_style_context_add_class (context, "spinbutton"); + else if (strcmp (detail, "spinbutton_up") == 0) + { + fp_gtk_style_context_add_class (context, "spinbutton"); + fp_gtk_style_context_add_class (context, "button"); + fp_gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + } + else if (strcmp (detail, "spinbutton_down") == 0) + { + fp_gtk_style_context_add_class (context, "spinbutton"); + fp_gtk_style_context_add_class (context, "button"); + fp_gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + } + else if ((detail[0] == 'h' || detail[0] == 'v') && + strncmp (&detail[1], "scrollbar_", 9) == 0) + { + fp_gtk_style_context_add_class (context, "button"); + fp_gtk_style_context_add_class (context, "scrollbar"); + } + else if (strcmp (detail, "slider") == 0) + { + fp_gtk_style_context_add_class (context, "slider"); + fp_gtk_style_context_add_class (context, "scrollbar"); + } + else if (strcmp (detail, "vscale") == 0 || + strcmp (detail, "hscale") == 0) + { + fp_gtk_style_context_add_class (context, "slider"); + fp_gtk_style_context_add_class (context, "scale"); + } + else if (strcmp (detail, "menuitem") == 0) + { + fp_gtk_style_context_add_class (context, "menuitem"); + fp_gtk_style_context_add_class (context, "menu"); + } + else if (strcmp (detail, "menu") == 0) + { + fp_gtk_style_context_add_class (context, "popup"); + fp_gtk_style_context_add_class (context, "menu"); + } + else if (strcmp (detail, "accellabel") == 0) + fp_gtk_style_context_add_class (context, "accelerator"); + else if (strcmp (detail, "menubar") == 0) + fp_gtk_style_context_add_class (context, "menubar"); + else if (strcmp (detail, "base") == 0) + fp_gtk_style_context_add_class (context, "background"); + else if (strcmp (detail, "bar") == 0 || + strcmp (detail, "progressbar") == 0) + fp_gtk_style_context_add_class (context, "progressbar"); + else if (strcmp (detail, "toolbar") == 0) + fp_gtk_style_context_add_class (context, "toolbar"); + else if (strcmp (detail, "handlebox_bin") == 0) + fp_gtk_style_context_add_class (context, "dock"); + else if (strcmp (detail, "notebook") == 0) + fp_gtk_style_context_add_class (context, "notebook"); + else if (strcmp (detail, "tab") == 0) + { + fp_gtk_style_context_add_class (context, "notebook"); + fp_gtk_style_context_add_region (context, "tab", 0); + } else if (strcmp (detail, "paned") == 0) { + fp_gtk_style_context_add_class (context, "pane-separator"); + } + else if (fp_g_str_has_prefix (detail, "cell")) + { + GtkRegionFlags row, col; + gboolean ruled = FALSE; + gchar** tokens; + guint i; + + tokens = fp_g_strsplit (detail, "_", -1); + row = col = 0; + i = 0; + + while (tokens[i]) + { + if (strcmp (tokens[i], "even") == 0) + row |= GTK_REGION_EVEN; + else if (strcmp (tokens[i], "odd") == 0) + row |= GTK_REGION_ODD; + else if (strcmp (tokens[i], "start") == 0) + col |= GTK_REGION_FIRST; + else if (strcmp (tokens[i], "end") == 0) + col |= GTK_REGION_LAST; + else if (strcmp (tokens[i], "ruled") == 0) + ruled = TRUE; + else if (strcmp (tokens[i], "sorted") == 0) + col |= GTK_REGION_SORTED; + + i++; + } + + if (!ruled) + row &= ~(GTK_REGION_EVEN | GTK_REGION_ODD); + + fp_gtk_style_context_add_class (context, "cell"); + fp_gtk_style_context_add_region (context, "row", row); + fp_gtk_style_context_add_region (context, "column", col); + + fp_g_strfreev (tokens); + } +} + +static gboolean gtk3_get_drawable_data(JNIEnv *env, jintArray pixelArray, + int x, jint y, jint width, jint height, jint jwidth, int dx, int dy, + jint scale) { + GdkPixbuf *pixbuf; + jint *ary; + + GdkWindow *root = (*fp_gdk_get_default_root_window)(); + pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(root, x, y, width, height); + if (pixbuf && scale != 1) { + GdkPixbuf *scaledPixbuf; + x /= scale; + y /= scale; + width /= scale; + height /= scale; + dx /= scale; + dy /= scale; + scaledPixbuf = (*fp_gdk_pixbuf_scale_simple)(pixbuf, width, height, + GDK_INTERP_BILINEAR); + (*fp_g_object_unref)(pixbuf); + pixbuf = scaledPixbuf; + } + + if (pixbuf) { + int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); + int stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); + if ((*fp_gdk_pixbuf_get_width)(pixbuf) == width + && (*fp_gdk_pixbuf_get_height)(pixbuf) == height + && (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf) == 8 + && (*fp_gdk_pixbuf_get_colorspace)(pixbuf) == GDK_COLORSPACE_RGB + && nchan >= 3 + ) { + guchar *p, *pix = (*fp_gdk_pixbuf_get_pixels)(pixbuf); + ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL); + if (ary) { + jint _x, _y; + int index; + for (_y = 0; _y < height; _y++) { + for (_x = 0; _x < width; _x++) { + p = pix + _y * stride + _x * nchan; + + index = (_y + dy) * jwidth + (_x + dx); + ary[index] = 0xff000000 + | (p[0] << 16) + | (p[1] << 8) + | (p[2]); + + } + } + (*env)->ReleasePrimitiveArrayCritical(env, pixelArray, ary, 0); + } + } + (*fp_g_object_unref)(pixbuf); + } + return JNI_FALSE; +} + +static GdkWindow* gtk3_get_window(void *widget) { + return fp_gtk_widget_get_window((GtkWidget*)widget); +} + +static void gtk3_init(GtkApi* gtk) { + gtk->version = GTK_3; + + gtk->show_uri_load = >k3_show_uri_load; + gtk->unload = >k3_unload; + gtk->flush_event_loop = &flush_gtk_event_loop; + gtk->gtk_check_version = fp_gtk_check_version; + gtk->get_setting = >k3_get_setting; + + gtk->paint_arrow = >k3_paint_arrow; + gtk->paint_box = >k3_paint_box; + gtk->paint_box_gap = >k3_paint_box_gap; + gtk->paint_expander = >k3_paint_expander; + gtk->paint_extension = >k3_paint_extension; + gtk->paint_flat_box = >k3_paint_flat_box; + gtk->paint_focus = >k3_paint_focus; + gtk->paint_handle = >k3_paint_handle; + gtk->paint_hline = >k3_paint_hline; + gtk->paint_vline = >k3_paint_vline; + gtk->paint_option = >k3_paint_option; + gtk->paint_shadow = >k3_paint_shadow; + gtk->paint_slider = >k3_paint_slider; + gtk->paint_background = >k3_paint_background; + gtk->paint_check = >k3_paint_check; + gtk->set_range_value = >k3_set_range_value; + + gtk->init_painting = >k3_init_painting; + gtk->copy_image = >k3_copy_image; + + gtk->get_xthickness = >k3_get_xthickness; + gtk->get_ythickness = >k3_get_ythickness; + gtk->get_color_for_state = >k3_get_color_for_state; + gtk->get_class_value = >k3_get_class_value; + + gtk->get_pango_font_name = >k3_get_pango_font_name; + gtk->get_icon_data = >k3_get_icon_data; + gtk->get_file_icon_data = >k3_get_file_icon_data; + gtk->gdk_threads_enter = fp_gdk_threads_enter; + gtk->gdk_threads_leave = fp_gdk_threads_leave; + gtk->gtk_show_uri = fp_gtk_show_uri; + gtk->get_drawable_data = >k3_get_drawable_data; + gtk->g_free = fp_g_free; + + gtk->gtk_file_chooser_get_filename = fp_gtk_file_chooser_get_filename; + gtk->gtk_widget_hide = fp_gtk_widget_hide; + gtk->gtk_main_quit = fp_gtk_main_quit; + gtk->gtk_file_chooser_dialog_new = fp_gtk_file_chooser_dialog_new; + gtk->gtk_file_chooser_set_current_folder = + fp_gtk_file_chooser_set_current_folder; + gtk->gtk_file_chooser_set_filename = fp_gtk_file_chooser_set_filename; + gtk->gtk_file_chooser_set_current_name = + fp_gtk_file_chooser_set_current_name; + gtk->gtk_file_filter_add_custom = fp_gtk_file_filter_add_custom; + gtk->gtk_file_chooser_set_filter = fp_gtk_file_chooser_set_filter; + gtk->gtk_file_chooser_get_type = fp_gtk_file_chooser_get_type; + gtk->gtk_file_filter_new = fp_gtk_file_filter_new; + gtk->gtk_file_chooser_set_do_overwrite_confirmation = + fp_gtk_file_chooser_set_do_overwrite_confirmation; + gtk->gtk_file_chooser_set_select_multiple = + fp_gtk_file_chooser_set_select_multiple; + gtk->gtk_file_chooser_get_current_folder = + fp_gtk_file_chooser_get_current_folder; + gtk->gtk_file_chooser_get_filenames = fp_gtk_file_chooser_get_filenames; + gtk->gtk_g_slist_length = fp_gtk_g_slist_length; + gtk->g_signal_connect_data = fp_g_signal_connect_data; + gtk->gtk_widget_show = fp_gtk_widget_show; + gtk->gtk_main = fp_gtk_main; + gtk->gtk_main_level = fp_gtk_main_level; + gtk->g_path_get_dirname = fp_g_path_get_dirname; + gtk->gdk_x11_drawable_get_xid = fp_gdk_x11_drawable_get_xid; + gtk->gtk_widget_destroy = fp_gtk_widget_destroy; + gtk->gtk_window_present = fp_gtk_window_present; + gtk->gtk_window_move = fp_gtk_window_move; + gtk->gtk_window_resize = fp_gtk_window_resize; + gtk->get_window = >k3_get_window; + + gtk->g_object_unref = fp_g_object_unref; + gtk->g_list_append = fp_g_list_append; + gtk->g_list_free = fp_g_list_free; + gtk->g_list_free_full = fp_g_list_free_full; +} diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h new file mode 100644 index 00000000000..1ffaa8fa9d0 --- /dev/null +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h @@ -0,0 +1,577 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +#ifndef _GTK3_INTERFACE_H +#define _GTK3_INTERFACE_H + +#include +#include +#include +#include "gtk_interface.h" + +#define LIGHTNESS_MULT 1.3 +#define DARKNESS_MULT 0.7 + +#define G_PI 3.1415926535897932384626433832795028841971693993751 + +typedef enum +{ + GTK_STATE_FLAG_NORMAL = 0, + GTK_STATE_FLAG_ACTIVE = 1 << 0, + GTK_STATE_FLAG_PRELIGHT = 1 << 1, + GTK_STATE_FLAG_SELECTED = 1 << 2, + GTK_STATE_FLAG_INSENSITIVE = 1 << 3, + GTK_STATE_FLAG_INCONSISTENT = 1 << 4, + GTK_STATE_FLAG_FOCUSED = 1 << 5, + GTK_STATE_FLAG_BACKDROP = 1 << 6, + GTK_STATE_FLAG_DIR_LTR = 1 << 7, + GTK_STATE_FLAG_DIR_RTL = 1 << 8, + GTK_STATE_FLAG_LINK = 1 << 9, + GTK_STATE_FLAG_VISITED = 1 << 10, + GTK_STATE_FLAG_CHECKED = 1 << 11 +} GtkStateFlags; + +typedef enum { + GTK_JUNCTION_NONE = 0, + GTK_JUNCTION_CORNER_TOPLEFT = 1 << 0, + GTK_JUNCTION_CORNER_TOPRIGHT = 1 << 1, + GTK_JUNCTION_CORNER_BOTTOMLEFT = 1 << 2, + GTK_JUNCTION_CORNER_BOTTOMRIGHT = 1 << 3, + GTK_JUNCTION_TOP = + (GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_TOPRIGHT), + GTK_JUNCTION_BOTTOM = + (GTK_JUNCTION_CORNER_BOTTOMLEFT | GTK_JUNCTION_CORNER_BOTTOMRIGHT), + GTK_JUNCTION_LEFT = + (GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMLEFT), + GTK_JUNCTION_RIGHT = + (GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMRIGHT) +} GtkJunctionSides; + +typedef enum { + GTK_REGION_EVEN = 1 << 0, + GTK_REGION_ODD = 1 << 1, + GTK_REGION_FIRST = 1 << 2, + GTK_REGION_LAST = 1 << 3, + GTK_REGION_ONLY = 1 << 4, + GTK_REGION_SORTED = 1 << 5 +} GtkRegionFlags; + +typedef enum +{ + GTK_WINDOW_TOPLEVEL, + GTK_WINDOW_POPUP +} GtkWindowType; + +typedef enum +{ + G_PARAM_READABLE = 1 << 0, + G_PARAM_WRITABLE = 1 << 1, + G_PARAM_CONSTRUCT = 1 << 2, + G_PARAM_CONSTRUCT_ONLY = 1 << 3, + G_PARAM_LAX_VALIDATION = 1 << 4, + G_PARAM_STATIC_NAME = 1 << 5 +} GParamFlags; + +typedef enum +{ + GTK_ICON_LOOKUP_NO_SVG = 1 << 0, + GTK_ICON_LOOKUP_FORCE_SVG = 1 << 1, + GTK_ICON_LOOKUP_USE_BUILTIN = 1 << 2, + GTK_ICON_LOOKUP_GENERIC_FALLBACK = 1 << 3, + GTK_ICON_LOOKUP_FORCE_SIZE = 1 << 4 +} GtkIconLookupFlags; + +typedef enum +{ + GTK_UPDATE_CONTINUOUS, + GTK_UPDATE_DISCONTINUOUS, + GTK_UPDATE_DELAYED +} GtkUpdateType; + +typedef enum +{ + GTK_PROGRESS_CONTINUOUS, + GTK_PROGRESS_DISCRETE +} GtkProgressBarStyle; + +typedef enum +{ + GTK_PROGRESS_LEFT_TO_RIGHT, + GTK_PROGRESS_RIGHT_TO_LEFT, + GTK_PROGRESS_BOTTOM_TO_TOP, + GTK_PROGRESS_TOP_TO_BOTTOM +} GtkProgressBarOrientation; + +typedef enum { + CAIRO_FORMAT_INVALID = -1, + CAIRO_FORMAT_ARGB32 = 0, + CAIRO_FORMAT_RGB24 = 1, + CAIRO_FORMAT_A8 = 2, + CAIRO_FORMAT_A1 = 3, + CAIRO_FORMAT_RGB16_565 = 4 +} cairo_format_t; + +/* We define all structure pointers to be void* */ +typedef void GdkPixbuf; +typedef void GMainContext; +typedef void GVfs; + +typedef void GdkColormap; +typedef void GdkDrawable; +typedef void GdkGC; +typedef void GdkPixmap; +typedef void GtkStyleContext; +typedef void GtkFixed; +typedef void GtkMenuItem; +typedef void GtkMenuShell; +typedef void GtkWidgetClass; +typedef void PangoFontDescription; +typedef void GtkSettings; +typedef void GtkStyleProvider; +typedef void cairo_pattern_t; +typedef void cairo_t; +typedef void cairo_surface_t; +typedef void GtkScrolledWindow; +typedef void GtkIconTheme; +typedef void GtkWidget; +typedef void GtkMisc; +typedef void GtkContainer; +typedef void GtkBin; +typedef void GtkAdjustment; +typedef void GtkRange; +typedef void GtkProgressBar; +typedef void GtkProgress; + +/* Some real structures */ +typedef struct +{ + guint32 pixel; + guint16 red; + guint16 green; + guint16 blue; +} GdkColor; + +typedef struct +{ + gdouble red; + gdouble green; + gdouble blue; + gdouble alpha; +} GdkRGBA; + +typedef struct { + gint fd; + gushort events; + gushort revents; +} GPollFD; + +typedef struct { + gint x; + gint y; + gint width; + gint height; +} GdkRectangle; + +typedef struct { + int x, y; + int width, height; +} GtkAllocation; + +typedef struct { + gint width; + gint height; +} GtkRequisition; + +typedef struct { + GtkWidgetClass *g_class; +} GTypeInstance; + +typedef struct { + gint16 left; + gint16 right; + gint16 top; + gint16 bottom; +} GtkBorder; + +typedef struct +{ + GType g_type; + union { + gint v_int; + guint v_uint; + glong v_long; + gulong v_ulong; + gint64 v_int64; + guint64 v_uint64; + gfloat v_float; + gdouble v_double; + gpointer v_pointer; + } data[2]; +} GValue; + +typedef struct { + GTypeInstance g_type_instance; + const gchar *name; + GParamFlags flags; + GType value_type; + GType owner_type; +} GParamSpec; + + +static gchar* (*fp_glib_check_version)(guint required_major, + guint required_minor, guint required_micro); + +/** + * Returns : + * NULL if the GTK+ library is compatible with the given version, or a string + * describing the version mismatch. + */ +static gchar* (*fp_gtk_check_version)(guint required_major, guint + required_minor, guint required_micro); + +static void (*fp_g_free)(gpointer mem); +static void (*fp_g_object_unref)(gpointer object); +static GdkWindow *(*fp_gdk_get_default_root_window) (void); + +static int (*fp_gdk_pixbuf_get_bits_per_sample)(const GdkPixbuf *pixbuf); +static guchar *(*fp_gdk_pixbuf_get_pixels)(const GdkPixbuf *pixbuf); +static gboolean (*fp_gdk_pixbuf_get_has_alpha)(const GdkPixbuf *pixbuf); +static int (*fp_gdk_pixbuf_get_height)(const GdkPixbuf *pixbuf); +static int (*fp_gdk_pixbuf_get_n_channels)(const GdkPixbuf *pixbuf); +static int (*fp_gdk_pixbuf_get_rowstride)(const GdkPixbuf *pixbuf); +static int (*fp_gdk_pixbuf_get_width)(const GdkPixbuf *pixbuf); +static GdkPixbuf *(*fp_gdk_pixbuf_new_from_file)(const char *filename, + GError **error); +static GdkColorspace (*fp_gdk_pixbuf_get_colorspace)(const GdkPixbuf *pixbuf); + +static GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkWindow *window, + int src_x, int src_y, int width, int height); +static GdkPixbuf *(*fp_gdk_pixbuf_scale_simple)(GdkPixbuf *src, + int dest_width, int dest_heigh, GdkInterpType interp_type); + + +static void (*fp_gtk_widget_destroy)(void *widget); +static void (*fp_gtk_window_present)(GtkWindow *window); +static void (*fp_gtk_window_move)(GtkWindow *window, gint x, gint y); +static void (*fp_gtk_window_resize)(GtkWindow *window, gint width, gint height); + +/** + * Function Pointers for GtkFileChooser + */ +static gchar* (*fp_gtk_file_chooser_get_filename)(GtkFileChooser *chooser); +static void (*fp_gtk_widget_hide)(void *widget); +static void (*fp_gtk_main_quit)(void); +static void* (*fp_gtk_file_chooser_dialog_new)(const gchar *title, + GtkWindow *parent, GtkFileChooserAction action, + const gchar *first_button_text, ...); +static gboolean (*fp_gtk_file_chooser_set_current_folder) + (GtkFileChooser *chooser, const gchar *filename); +static gboolean (*fp_gtk_file_chooser_set_filename)(GtkFileChooser *chooser, + const char *filename); +static void (*fp_gtk_file_chooser_set_current_name)(GtkFileChooser *chooser, + const gchar *name); +static void (*fp_gtk_file_filter_add_custom)(GtkFileFilter *filter, + GtkFileFilterFlags needed, GtkFileFilterFunc func, gpointer data, + GDestroyNotify notify); +static void (*fp_gtk_file_chooser_set_filter)(GtkFileChooser *chooser, + GtkFileFilter *filter); +static GType (*fp_gtk_file_chooser_get_type)(void); +static GtkFileFilter* (*fp_gtk_file_filter_new)(void); +static void (*fp_gtk_file_chooser_set_do_overwrite_confirmation)( + GtkFileChooser *chooser, gboolean do_overwrite_confirmation); +static void (*fp_gtk_file_chooser_set_select_multiple)( + GtkFileChooser *chooser, gboolean select_multiple); +static gchar* (*fp_gtk_file_chooser_get_current_folder) + (GtkFileChooser *chooser); +static GSList* (*fp_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser); +static guint (*fp_gtk_g_slist_length)(GSList *list); +static gulong (*fp_g_signal_connect_data)(gpointer instance, + const gchar *detailed_signal, GCallback c_handler, gpointer data, + GClosureNotify destroy_data, GConnectFlags connect_flags); +static void (*fp_gtk_widget_show)(void *widget); +static void (*fp_gtk_main)(void); +static guint (*fp_gtk_main_level)(void); +static gchar* (*fp_g_path_get_dirname) (const gchar *file_name); +static XID (*fp_gdk_x11_drawable_get_xid) (GdkWindow *drawable); + +static GList* (*fp_g_list_append) (GList *list, gpointer data); +static void (*fp_g_list_free) (GList *list); +static void (*fp_g_list_free_full) (GList *list, GDestroyNotify free_func); + +static void (*fp_gdk_threads_enter)(void); +static void (*fp_gdk_threads_leave)(void); + +static gboolean (*fp_gtk_show_uri)(GdkScreen *screen, const gchar *uri, + guint32 timestamp, GError **error); + +// Implementation functions prototypes +static void gtk3_init(GtkApi* gtk); +static GValue* (*fp_g_value_init)(GValue *value, GType g_type); +static gboolean (*fp_g_type_is_a)(GType type, GType is_a_type); +static gboolean (*fp_g_value_get_boolean)(const GValue *value); +static gchar (*fp_g_value_get_char)(const GValue *value); +static guchar (*fp_g_value_get_uchar)(const GValue *value); +static gint (*fp_g_value_get_int)(const GValue *value); +static guint (*fp_g_value_get_uint)(const GValue *value); +static glong (*fp_g_value_get_long)(const GValue *value); +static gulong (*fp_g_value_get_ulong)(const GValue *value); +static gint64 (*fp_g_value_get_int64)(const GValue *value); +static guint64 (*fp_g_value_get_uint64)(const GValue *value); +static gfloat (*fp_g_value_get_float)(const GValue *value); +static gdouble (*fp_g_value_get_double)(const GValue *value); +static const gchar* (*fp_g_value_get_string)(const GValue *value); +static gint (*fp_g_value_get_enum)(const GValue *value); +static guint (*fp_g_value_get_flags)(const GValue *value); +static GParamSpec* (*fp_g_value_get_param)(const GValue *value); +static gpointer* (*fp_g_value_get_boxed)(const GValue *value); +static gpointer* (*fp_g_value_get_pointer)(const GValue *value); +static void (*fp_g_object_get)(gpointer object, + const gchar* fpn, ...); +static void (*fp_g_object_set)(gpointer object, + const gchar *first_property_name, + ...); + +static gboolean (*fp_g_main_context_iteration)(GMainContext *context); +static gboolean (*fp_g_str_has_prefix)(const gchar *str, const gchar *prefix); +static gchar** (*fp_g_strsplit)(const gchar *string, const gchar *delimiter, + gint max_tokens); +static void (*fp_g_strfreev)(gchar **str_array); + + +static cairo_surface_t* (*fp_cairo_image_surface_create)(cairo_format_t format, + int width, int height); +static void (*fp_cairo_surface_destroy)(cairo_surface_t *surface); +static cairo_t* (*fp_cairo_create)(cairo_surface_t *target); +static void (*fp_cairo_destroy)(cairo_t *cr); +static void (*fp_cairo_fill)(cairo_t *cr); +static void (*fp_cairo_surface_flush)(cairo_surface_t *surface); +static void (*fp_cairo_rectangle)(cairo_t *cr, double x, double y, double width, + double height); +static void (*fp_cairo_set_source_rgb)(cairo_t *cr, double red, double green, + double blue); +static void (*fp_cairo_set_source_rgba)(cairo_t *cr, double red, double green, + double blue, double alpha); +static void (*fp_cairo_paint)(cairo_t *cr); +static void (*fp_cairo_clip)(cairo_t *cr); +static unsigned char* (*fp_cairo_image_surface_get_data)( + cairo_surface_t *surface); +static int (*fp_cairo_image_surface_get_stride) (cairo_surface_t *surface); +static GdkPixbuf* (*fp_gdk_pixbuf_get_from_surface)(cairo_surface_t *surface, + gint src_x, gint src_y, gint width, gint height); +static GtkStateType (*fp_gtk_widget_get_state)(GtkWidget *widget); +static void (*fp_gtk_widget_set_state)(GtkWidget *widget, GtkStateType state); +static gboolean (*fp_gtk_widget_is_focus)(GtkWidget *widget); +static void (*fp_gtk_widget_set_allocation)(GtkWidget *widget, + const GtkAllocation *allocation); +static GtkWidget* (*fp_gtk_widget_get_parent)(GtkWidget *widget); +static GtkStyleContext* (*fp_gtk_widget_get_style_context)(GtkWidget *widget); +static void (*fp_gtk_style_context_get_color)(GtkStyleContext *context, + GtkStateFlags state, GdkRGBA *color); +static void (*fp_gtk_style_context_get_background_color) + (GtkStyleContext *context, GtkStateFlags state, GdkRGBA *color); +static void (*fp_gtk_style_context_get)(GtkStyleContext *context, + GtkStateFlags state, ...); +static GtkStateFlags (*fp_gtk_widget_get_state_flags)(GtkWidget* widget); +static void (*fp_gtk_style_context_set_state)(GtkStyleContext* style, + GtkStateFlags flags); +static void (*fp_gtk_style_context_add_class)(GtkStyleContext *context, + const gchar *class_name); +static void (*fp_gtk_style_context_save)(GtkStyleContext *context); +static void (*fp_gtk_style_context_restore)(GtkStyleContext *context); +static void (*fp_gtk_render_check)(GtkStyleContext *context, cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height); +static void (*fp_gtk_render_option)(GtkStyleContext *context, cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height); +static void (*fp_gtk_render_extension)(GtkStyleContext *context, cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height, + GtkPositionType gap_side); +static void (*fp_gtk_render_expander)(GtkStyleContext *context, cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height); +static void (*fp_gtk_render_frame_gap)(GtkStyleContext *context, cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height, + GtkPositionType gap_side, gdouble xy0_gap, + gdouble xy1_gap); +static void (*fp_gtk_render_line)(GtkStyleContext *context, cairo_t *cr, + gdouble x0, gdouble y0, gdouble x1, gdouble y1); +static GdkPixbuf* (*fp_gtk_widget_render_icon_pixbuf)(GtkWidget *widget, + const gchar *stock_id, GtkIconSize size); +static cairo_surface_t* (*fp_gdk_window_create_similar_image_surface)( + GdkWindow *window, cairo_format_t format, int width, + int height, int scale); +static cairo_surface_t* (*fp_gdk_window_create_similar_surface)( + GdkWindow *window, cairo_format_t format, + int width, int height); +static GdkWindow* (*fp_gtk_widget_get_window)(GtkWidget *widget); +static GtkSettings *(*fp_gtk_settings_get_for_screen)(GdkScreen *screen); +static GdkScreen *(*fp_gtk_widget_get_screen)(GtkWidget *widget); +static GtkStyleProvider* (*fp_gtk_css_provider_get_named)(const gchar *name, + const gchar *variant); +static void (*fp_gtk_style_context_add_provider)(GtkStyleContext *context, + GtkStyleProvider *provider, guint priority); +static void (*fp_gtk_render_frame)(GtkStyleContext *context,cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height); +static void (*fp_gtk_render_focus)(GtkStyleContext *context,cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height); +static void (*fp_gtk_render_handle)(GtkStyleContext *context,cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height); +static void (*fp_gtk_style_context_get_property)(GtkStyleContext *context, + const gchar *property, GtkStateFlags state, GValue *value); +static void (*fp_gtk_render_activity)(GtkStyleContext *context, cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height); +static void (*fp_gtk_render_background)(GtkStyleContext *context, cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height); +static gboolean (*fp_gtk_style_context_has_class)(GtkStyleContext *context, + const gchar *class_name); +static void transform_detail_string (const gchar *detail, + GtkStyleContext *context); +void (*fp_gtk_style_context_set_junction_sides)(GtkStyleContext *context, + GtkJunctionSides sides); +void (*fp_gtk_style_context_add_region)(GtkStyleContext *context, + const gchar *region_name, GtkRegionFlags flags); +void (*fp_gtk_render_arrow)(GtkStyleContext *context, cairo_t *cr, + gdouble angle, gdouble x, gdouble y, gdouble size); +void (*fp_gtk_bin_set_child)(GtkBin *bin, GtkWidget *widget); +void (*fp_gtk_scrolled_window_set_shadow_type)( + GtkScrolledWindow *scrolled_window, GtkShadowType type); +static void (*fp_gtk_render_slider)(GtkStyleContext *context, cairo_t *cr, + gdouble x, gdouble y, gdouble width, gdouble height, + GtkOrientation orientation); +static void (*fp_gtk_style_context_get_padding)(GtkStyleContext *self, + GtkStateFlags state, GtkBorder* padding); +static void (*fp_gtk_range_set_inverted)(GtkRange *range, gboolean setting); +static PangoFontDescription* (*fp_gtk_style_context_get_font)( + GtkStyleContext *context, GtkStateFlags state); +static int (*fp_gtk_widget_get_allocated_width)(GtkWidget *widget); +static int (*fp_gtk_widget_get_allocated_height)(GtkWidget *widget); +static GtkIconTheme* (*fp_gtk_icon_theme_get_default)(void); +static GdkPixbuf* (*fp_gtk_icon_theme_load_icon)(GtkIconTheme *icon_theme, + const gchar *icon_name, gint size, + GtkIconLookupFlags flags, GError **error); +static void (*fp_gtk_adjustment_set_lower)(GtkAdjustment *adjustment, + gdouble lower); +static void (*fp_gtk_adjustment_set_page_increment)(GtkAdjustment *adjustment, + gdouble page_increment); +static void (*fp_gtk_adjustment_set_page_size)(GtkAdjustment *adjustment, + gdouble page_size); +static void (*fp_gtk_adjustment_set_step_increment)(GtkAdjustment *adjustment, + gdouble step_increment); +static void (*fp_gtk_adjustment_set_upper)(GtkAdjustment *adjustment, + gdouble upper); +static void (*fp_gtk_adjustment_set_value)(GtkAdjustment *adjustment, + gdouble value); +static GdkGC *(*fp_gdk_gc_new)(GdkDrawable*); +static void (*fp_gdk_rgb_gc_set_foreground)(GdkGC*, guint32); +static void (*fp_gdk_draw_rectangle)(GdkDrawable*, GdkGC*, gboolean, + gint, gint, gint, gint); +static GdkPixbuf *(*fp_gdk_pixbuf_new)(GdkColorspace colorspace, + gboolean has_alpha, int bits_per_sample, int width, int height); +static void (*fp_gdk_drawable_get_size)(GdkDrawable *drawable, + gint* width, gint* height); +static gboolean (*fp_gtk_init_check)(int* argc, char** argv); + +/* Widget creation */ +static GtkWidget* (*fp_gtk_arrow_new)(GtkArrowType arrow_type, + GtkShadowType shadow_type); +static GtkWidget* (*fp_gtk_button_new)(); +static GtkWidget* (*fp_gtk_check_button_new)(); +static GtkWidget* (*fp_gtk_check_menu_item_new)(); +static GtkWidget* (*fp_gtk_color_selection_dialog_new)(const gchar* title); +static GtkWidget* (*fp_gtk_combo_box_new)(); +static GtkWidget* (*fp_gtk_combo_box_entry_new)(); +static GtkWidget* (*fp_gtk_entry_new)(); +static GtkWidget* (*fp_gtk_fixed_new)(); +static GtkWidget* (*fp_gtk_handle_box_new)(); +static GtkWidget* (*fp_gtk_hpaned_new)(); +static GtkWidget* (*fp_gtk_vpaned_new)(); +static GtkWidget* (*fp_gtk_scale_new)(GtkOrientation orientation, + GtkAdjustment* adjustment); +static GtkWidget* (*fp_gtk_hscrollbar_new)(GtkAdjustment* adjustment); +static GtkWidget* (*fp_gtk_vscrollbar_new)(GtkAdjustment* adjustment); +static GtkWidget* (*fp_gtk_hseparator_new)(); +static GtkWidget* (*fp_gtk_vseparator_new)(); +static GtkWidget* (*fp_gtk_image_new)(); +static GtkWidget* (*fp_gtk_label_new)(const gchar* str); +static GtkWidget* (*fp_gtk_menu_new)(); +static GtkWidget* (*fp_gtk_menu_bar_new)(); +static GtkWidget* (*fp_gtk_menu_item_new)(); +static GtkWidget* (*fp_gtk_notebook_new)(); +static GtkWidget* (*fp_gtk_progress_bar_new)(); +static GtkWidget* (*fp_gtk_progress_bar_set_orientation)( + GtkProgressBar *pbar, + GtkProgressBarOrientation orientation); +static GtkWidget* (*fp_gtk_radio_button_new)(GSList *group); +static GtkWidget* (*fp_gtk_radio_menu_item_new)(GSList *group); +static GtkWidget* (*fp_gtk_scrolled_window_new)(GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +static GtkWidget* (*fp_gtk_separator_menu_item_new)(); +static GtkWidget* (*fp_gtk_separator_tool_item_new)(); +static GtkWidget* (*fp_gtk_text_view_new)(); +static GtkWidget* (*fp_gtk_toggle_button_new)(); +static GtkWidget* (*fp_gtk_toolbar_new)(); +static GtkWidget* (*fp_gtk_tree_view_new)(); +static GtkWidget* (*fp_gtk_viewport_new)(GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +static GtkWidget* (*fp_gtk_window_new)(GtkWindowType type); +static GtkWidget* (*fp_gtk_dialog_new)(); +static GtkWidget* (*fp_gtk_spin_button_new)(GtkAdjustment *adjustment, + gdouble climb_rate, guint digits); +static GtkWidget* (*fp_gtk_frame_new)(const gchar *label); + +/* Other widget operations */ +static GtkAdjustment* (*fp_gtk_adjustment_new)(gdouble value, + gdouble lower, gdouble upper, gdouble step_increment, + gdouble page_increment, gdouble page_size); +static void (*fp_gtk_container_add)(GtkContainer *window, GtkWidget *widget); +static void (*fp_gtk_menu_shell_append)(GtkMenuShell *menu_shell, + GtkWidget *child); +static void (*fp_gtk_menu_item_set_submenu)(GtkMenuItem *menu_item, + GtkWidget *submenu); +static void (*fp_gtk_widget_realize)(GtkWidget *widget); +static GdkPixbuf* (*fp_gtk_widget_render_icon)(GtkWidget *widget, + const gchar *stock_id, GtkIconSize size, const gchar *detail); +static void (*fp_gtk_widget_set_name)(GtkWidget *widget, const gchar *name); +static void (*fp_gtk_widget_set_parent)(GtkWidget *widget, GtkWidget *parent); +static void (*fp_gtk_widget_set_direction)(GtkWidget *widget, + GtkTextDirection direction); +static void (*fp_gtk_widget_style_get)(GtkWidget *widget, + const gchar *first_property_name, ...); +static void (*fp_gtk_widget_class_install_style_property)( + GtkWidgetClass* class, GParamSpec *pspec); +static GParamSpec* (*fp_gtk_widget_class_find_style_property)( + GtkWidgetClass* class, const gchar* property_name); +static void (*fp_gtk_widget_style_get_property)(GtkWidget* widget, + const gchar* property_name, GValue* value); +static char* (*fp_pango_font_description_to_string)( + const PangoFontDescription* fd); +static GtkSettings* (*fp_gtk_settings_get_default)(); +static GtkSettings* (*fp_gtk_widget_get_settings)(GtkWidget *widget); +static GType (*fp_gtk_border_get_type)(); +static void (*fp_gtk_arrow_set)(GtkWidget* arrow, + GtkArrowType arrow_type, + GtkShadowType shadow_type); +static void (*fp_gtk_widget_size_request)(GtkWidget *widget, + GtkRequisition *requisition); +static GtkAdjustment* (*fp_gtk_range_get_adjustment)(GtkRange* range); + +#endif /* !_GTK3_INTERFACE_H */ diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.c new file mode 100644 index 00000000000..0a136b39768 --- /dev/null +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +#include +#include +#include "jvm_md.h" +#include "gtk_interface.h" + +GtkApi* gtk2_load(JNIEnv *env, const char* lib_name); +GtkApi* gtk3_load(JNIEnv *env, const char* lib_name); + +gboolean gtk2_check(const char* lib_name, int flags); +gboolean gtk3_check(const char* lib_name, int flags); + +GtkApi *gtk; + +typedef struct { + GtkVersion version; + const char* name; + const char* vname; + GtkApi* (*load)(JNIEnv *env, const char* lib_name); + gboolean (*check)(const char* lib_name, int flags); +} GtkLib; + +static GtkLib libs[] = { + { + GTK_2, + JNI_LIB_NAME("gtk-x11-2.0"), + VERSIONED_JNI_LIB_NAME("gtk-x11-2.0", "0"), + >k2_load, + >k2_check + }, + { + GTK_3, + JNI_LIB_NAME("gtk-3"), + VERSIONED_JNI_LIB_NAME("gtk-3", "0"), + >k3_load, + >k3_check + }, + { + 0, + NULL, + NULL, + NULL, + NULL + } +}; + +static GtkLib* get_loaded() { + GtkLib* lib = libs; + while(!gtk && lib->version) { + if (lib->check(lib->vname, RTLD_NOLOAD)) { + return lib; + } + if (lib->check(lib->name, RTLD_NOLOAD)) { + return lib; + } + lib++; + } + return NULL; +} + +gboolean gtk_load(JNIEnv *env, GtkVersion version, gboolean verbose) { + if (gtk == NULL) { + GtkLib* lib = get_loaded(); + if (lib) { + if (version != GTK_ANY && lib->version != version) { + if (verbose) { + fprintf(stderr, "WARNING: Cannot load GTK%d library: \ + GTK%d has already been loaded\n", version, lib->version); + } + return FALSE; + } + if (verbose) { + fprintf(stderr, "Looking for GTK%d library...\n", version); + } + gtk = lib->load(env, lib->vname); + if (!gtk) { + gtk = lib->load(env, lib->name); + } + } else { + lib = libs; + while (!gtk && lib->version) { + if (version == GTK_ANY || lib->version == version) { + if (verbose) { + fprintf(stderr, "Looking for GTK%d library...\n", + lib->version); + } + gtk = lib->load(env, lib->vname); + if (!gtk) { + gtk = lib->load(env, lib->name); + } + if (verbose && !gtk) { + fprintf(stderr, "Not found.\n"); + } + } + lib++; + } + lib--; + } + if (verbose) { + if (gtk) { + fprintf(stderr, "GTK%d library loaded.\n", lib->version); + } else { + fprintf(stderr, "Failed to load GTK library.\n"); + } + } + } + return gtk != NULL; +} + +static gboolean check_version(GtkVersion version, int flags) { + GtkLib* lib = libs; + while (lib->version) { + if (version == GTK_ANY || lib->version == version) { + if (lib->check(lib->vname, flags)) { + return TRUE; + } + if (lib->check(lib->name, flags)) { + return TRUE; + } + } + lib++; + } + return FALSE; +} + +gboolean gtk_check_version(GtkVersion version) { + if (gtk) { + return TRUE; + } + if (check_version(version, RTLD_NOLOAD)) { + return TRUE; + } + return check_version(version, RTLD_LAZY | RTLD_LOCAL); +} + diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h new file mode 100644 index 00000000000..e39e172f7e5 --- /dev/null +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +#ifndef _GTK_INTERFACE_H +#define _GTK_INTERFACE_H + +#include +#include + +#ifndef FALSE +#define FALSE (0) +#define TRUE (!FALSE) +#endif + +#define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip) +#define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) \ + (_G_TYPE_CIC ((instance), (g_type), c_type)) +#define GTK_TYPE_FILE_CHOOSER (fp_gtk_file_chooser_get_type ()) +#define GTK_FILE_CHOOSER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_CHOOSER, GtkFileChooser)) +#define G_CALLBACK(f) ((GCallback) (f)) +#define G_TYPE_FUNDAMENTAL_SHIFT (2) +#define G_TYPE_MAKE_FUNDAMENTAL(x) ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT)) +#define G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20) +#define GTK_STOCK_CANCEL "gtk-cancel" +#define GTK_STOCK_SAVE "gtk-save" +#define GTK_STOCK_OPEN "gtk-open" +#define GDK_CURRENT_TIME 0L + +#define G_TYPE_INVALID G_TYPE_MAKE_FUNDAMENTAL (0) +#define G_TYPE_NONE G_TYPE_MAKE_FUNDAMENTAL (1) +#define G_TYPE_INTERFACE G_TYPE_MAKE_FUNDAMENTAL (2) +#define G_TYPE_CHAR G_TYPE_MAKE_FUNDAMENTAL (3) +#define G_TYPE_UCHAR G_TYPE_MAKE_FUNDAMENTAL (4) +#define G_TYPE_BOOLEAN G_TYPE_MAKE_FUNDAMENTAL (5) +#define G_TYPE_INT G_TYPE_MAKE_FUNDAMENTAL (6) +#define G_TYPE_UINT G_TYPE_MAKE_FUNDAMENTAL (7) +#define G_TYPE_LONG G_TYPE_MAKE_FUNDAMENTAL (8) +#define G_TYPE_ULONG G_TYPE_MAKE_FUNDAMENTAL (9) +#define G_TYPE_INT64 G_TYPE_MAKE_FUNDAMENTAL (10) +#define G_TYPE_UINT64 G_TYPE_MAKE_FUNDAMENTAL (11) +#define G_TYPE_ENUM G_TYPE_MAKE_FUNDAMENTAL (12) +#define G_TYPE_FLAGS G_TYPE_MAKE_FUNDAMENTAL (13) +#define G_TYPE_FLOAT G_TYPE_MAKE_FUNDAMENTAL (14) +#define G_TYPE_DOUBLE G_TYPE_MAKE_FUNDAMENTAL (15) +#define G_TYPE_STRING G_TYPE_MAKE_FUNDAMENTAL (16) +#define G_TYPE_POINTER G_TYPE_MAKE_FUNDAMENTAL (17) +#define G_TYPE_BOXED G_TYPE_MAKE_FUNDAMENTAL (18) +#define G_TYPE_PARAM G_TYPE_MAKE_FUNDAMENTAL (19) +#define G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20) + +#define GTK_TYPE_BORDER ((*fp_gtk_border_get_type)()) + +#define G_TYPE_FUNDAMENTAL_SHIFT (2) +#define G_TYPE_MAKE_FUNDAMENTAL(x) ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT)) + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define CONV_BUFFER_SIZE 128 +#define NO_SYMBOL_EXCEPTION 1 + +/* basic types */ +typedef char gchar; +typedef short gshort; +typedef int gint; +typedef long glong; +typedef float gfloat; +typedef double gdouble; +typedef void* gpointer; +typedef gint gboolean; +typedef signed char gint8; +typedef signed short gint16; +typedef signed int gint32; +typedef unsigned char guchar; +typedef unsigned char guint8; +typedef unsigned short gushort; +typedef unsigned short guint16; +typedef unsigned int guint; +typedef unsigned int guint32; +typedef unsigned int gsize; +typedef unsigned long gulong; +typedef signed long long gint64; +typedef unsigned long long guint64; +typedef gulong GType; + +typedef struct _GList GList; +struct _GList +{ + gpointer data; + GList *next; + GList *prev; +}; + +typedef struct _GSList GSList; +struct _GSList { + gpointer data; + GSList *next; +}; + +typedef enum { + BUTTON, /* GtkButton */ + CHECK_BOX, /* GtkCheckButton */ + CHECK_BOX_MENU_ITEM, /* GtkCheckMenuItem */ + COLOR_CHOOSER, /* GtkColorSelectionDialog */ + COMBO_BOX, /* GtkComboBox */ + COMBO_BOX_ARROW_BUTTON, /* GtkComboBoxEntry */ + COMBO_BOX_TEXT_FIELD, /* GtkComboBoxEntry */ + DESKTOP_ICON, /* GtkLabel */ + DESKTOP_PANE, /* GtkContainer */ + EDITOR_PANE, /* GtkTextView */ + FORMATTED_TEXT_FIELD, /* GtkEntry */ + HANDLE_BOX, /* GtkHandleBox */ + HPROGRESS_BAR, /* GtkProgressBar */ + HSCROLL_BAR, /* GtkHScrollbar */ + HSCROLL_BAR_BUTTON_LEFT, /* GtkHScrollbar */ + HSCROLL_BAR_BUTTON_RIGHT, /* GtkHScrollbar */ + HSCROLL_BAR_TRACK, /* GtkHScrollbar */ + HSCROLL_BAR_THUMB, /* GtkHScrollbar */ + HSEPARATOR, /* GtkHSeparator */ + HSLIDER, /* GtkHScale */ + HSLIDER_TRACK, /* GtkHScale */ + HSLIDER_THUMB, /* GtkHScale */ + HSPLIT_PANE_DIVIDER, /* GtkHPaned */ + INTERNAL_FRAME, /* GtkWindow */ + INTERNAL_FRAME_TITLE_PANE, /* GtkLabel */ + IMAGE, /* GtkImage */ + LABEL, /* GtkLabel */ + LIST, /* GtkTreeView */ + MENU, /* GtkMenu */ + MENU_BAR, /* GtkMenuBar */ + MENU_ITEM, /* GtkMenuItem */ + MENU_ITEM_ACCELERATOR, /* GtkLabel */ + OPTION_PANE, /* GtkMessageDialog */ + PANEL, /* GtkContainer */ + PASSWORD_FIELD, /* GtkEntry */ + POPUP_MENU, /* GtkMenu */ + POPUP_MENU_SEPARATOR, /* GtkSeparatorMenuItem */ + RADIO_BUTTON, /* GtkRadioButton */ + RADIO_BUTTON_MENU_ITEM, /* GtkRadioMenuItem */ + ROOT_PANE, /* GtkContainer */ + SCROLL_PANE, /* GtkScrolledWindow */ + SPINNER, /* GtkSpinButton */ + SPINNER_ARROW_BUTTON, /* GtkSpinButton */ + SPINNER_TEXT_FIELD, /* GtkSpinButton */ + SPLIT_PANE, /* GtkPaned */ + TABBED_PANE, /* GtkNotebook */ + TABBED_PANE_TAB_AREA, /* GtkNotebook */ + TABBED_PANE_CONTENT, /* GtkNotebook */ + TABBED_PANE_TAB, /* GtkNotebook */ + TABLE, /* GtkTreeView */ + TABLE_HEADER, /* GtkButton */ + TEXT_AREA, /* GtkTextView */ + TEXT_FIELD, /* GtkEntry */ + TEXT_PANE, /* GtkTextView */ + TITLED_BORDER, /* GtkFrame */ + TOGGLE_BUTTON, /* GtkToggleButton */ + TOOL_BAR, /* GtkToolbar */ + TOOL_BAR_DRAG_WINDOW, /* GtkToolbar */ + TOOL_BAR_SEPARATOR, /* GtkSeparatorToolItem */ + TOOL_TIP, /* GtkWindow */ + TREE, /* GtkTreeView */ + TREE_CELL, /* GtkTreeView */ + VIEWPORT, /* GtkViewport */ + VPROGRESS_BAR, /* GtkProgressBar */ + VSCROLL_BAR, /* GtkVScrollbar */ + VSCROLL_BAR_BUTTON_UP, /* GtkVScrollbar */ + VSCROLL_BAR_BUTTON_DOWN, /* GtkVScrollbar */ + VSCROLL_BAR_TRACK, /* GtkVScrollbar */ + VSCROLL_BAR_THUMB, /* GtkVScrollbar */ + VSEPARATOR, /* GtkVSeparator */ + VSLIDER, /* GtkVScale */ + VSLIDER_TRACK, /* GtkVScale */ + VSLIDER_THUMB, /* GtkVScale */ + VSPLIT_PANE_DIVIDER, /* GtkVPaned */ + WIDGET_TYPE_SIZE +} WidgetType; + +typedef enum +{ + _GTK_ARROW_TYPE, + _GTK_BUTTON_TYPE, + _GTK_CHECK_BUTTON_TYPE, + _GTK_CHECK_MENU_ITEM_TYPE, + _GTK_COLOR_SELECTION_DIALOG_TYPE, + _GTK_COMBO_BOX_TYPE, + _GTK_COMBO_BOX_ARROW_BUTTON_TYPE, + _GTK_COMBO_BOX_TEXT_FIELD_TYPE, + _GTK_CONTAINER_TYPE, + _GTK_ENTRY_TYPE, + _GTK_FRAME_TYPE, + _GTK_HANDLE_BOX_TYPE, + _GTK_HPANED_TYPE, + _GTK_HPROGRESS_BAR_TYPE, + _GTK_HSCALE_TYPE, + _GTK_HSCROLLBAR_TYPE, + _GTK_HSEPARATOR_TYPE, + _GTK_IMAGE_TYPE, + _GTK_MENU_TYPE, + _GTK_MENU_BAR_TYPE, + _GTK_MENU_ITEM_TYPE, + _GTK_NOTEBOOK_TYPE, + _GTK_LABEL_TYPE, + _GTK_RADIO_BUTTON_TYPE, + _GTK_RADIO_MENU_ITEM_TYPE, + _GTK_SCROLLED_WINDOW_TYPE, + _GTK_SEPARATOR_MENU_ITEM_TYPE, + _GTK_SEPARATOR_TOOL_ITEM_TYPE, + _GTK_SPIN_BUTTON_TYPE, + _GTK_TEXT_VIEW_TYPE, + _GTK_TOGGLE_BUTTON_TYPE, + _GTK_TOOLBAR_TYPE, + _GTK_TOOLTIP_TYPE, + _GTK_TREE_VIEW_TYPE, + _GTK_VIEWPORT_TYPE, + _GTK_VPANED_TYPE, + _GTK_VPROGRESS_BAR_TYPE, + _GTK_VSCALE_TYPE, + _GTK_VSCROLLBAR_TYPE, + _GTK_VSEPARATOR_TYPE, + _GTK_WINDOW_TYPE, + _GTK_DIALOG_TYPE, + _GTK_WIDGET_TYPE_SIZE +} GtkWidgetType; + +typedef enum +{ + GTK_STATE_NORMAL, + GTK_STATE_ACTIVE, + GTK_STATE_PRELIGHT, + GTK_STATE_SELECTED, + GTK_STATE_INSENSITIVE, + GTK_STATE_INCONSISTENT, + GTK_STATE_FOCUSED +} GtkStateType; + +typedef enum +{ + GTK_SHADOW_NONE, + GTK_SHADOW_IN, + GTK_SHADOW_OUT, + GTK_SHADOW_ETCHED_IN, + GTK_SHADOW_ETCHED_OUT +} GtkShadowType; + +typedef enum +{ + GTK_EXPANDER_COLLAPSED, + GTK_EXPANDER_SEMI_COLLAPSED, + GTK_EXPANDER_SEMI_EXPANDED, + GTK_EXPANDER_EXPANDED +} GtkExpanderStyle; + +typedef enum +{ + GTK_ICON_SIZE_INVALID, + GTK_ICON_SIZE_MENU, + GTK_ICON_SIZE_SMALL_TOOLBAR, + GTK_ICON_SIZE_LARGE_TOOLBAR, + GTK_ICON_SIZE_BUTTON, + GTK_ICON_SIZE_DND, + GTK_ICON_SIZE_DIALOG +} GtkIconSize; + +typedef enum +{ + GTK_ORIENTATION_HORIZONTAL, + GTK_ORIENTATION_VERTICAL +} GtkOrientation; + +typedef enum +{ + FOREGROUND, + BACKGROUND, + TEXT_FOREGROUND, + TEXT_BACKGROUND, + FOCUS, + LIGHT, + DARK, + MID, + BLACK, + WHITE +} ColorType; + +typedef enum +{ + GTK_FONT_NAME, + GTK_ICON_SIZES, + GTK_CURSOR_BLINK, + GTK_CURSOR_BLINK_TIME +} Setting; + +typedef enum +{ + GTK_ARROW_UP, + GTK_ARROW_DOWN, + GTK_ARROW_LEFT, + GTK_ARROW_RIGHT, + GTK_ARROW_NONE +} GtkArrowType; + +typedef enum +{ + GTK_TEXT_DIR_NONE, + GTK_TEXT_DIR_LTR, + GTK_TEXT_DIR_RTL +} GtkTextDirection; + +typedef enum +{ + GTK_POS_LEFT, + GTK_POS_RIGHT, + GTK_POS_TOP, + GTK_POS_BOTTOM +} GtkPositionType; + +/* SynthConstants */ +static const gint ENABLED = 1 << 0; +static const gint MOUSE_OVER = 1 << 1; +static const gint PRESSED = 1 << 2; +static const gint DISABLED = 1 << 3; +static const gint FOCUSED = 1 << 8; +static const gint SELECTED = 1 << 9; +static const gint DEFAULT = 1 << 10; + +typedef enum +{ + GTK_ANY, + GTK_1, + GTK_2, + GTK_3 +} GtkVersion; + +//------------------------------ + + + +typedef enum { + GTK_RESPONSE_NONE = -1, + GTK_RESPONSE_REJECT = -2, + GTK_RESPONSE_ACCEPT = -3, + GTK_RESPONSE_DELETE_EVENT = -4, + GTK_RESPONSE_OK = -5, + GTK_RESPONSE_CANCEL = -6, + GTK_RESPONSE_CLOSE = -7, + GTK_RESPONSE_YES = -8, + GTK_RESPONSE_NO = -9, + GTK_RESPONSE_APPLY = -10, + GTK_RESPONSE_HELP = -11 +} GtkResponseType; + +typedef enum { + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER +} GtkFileChooserAction; + +typedef enum { + GTK_FILE_FILTER_FILENAME = 1 << 0, + GTK_FILE_FILTER_URI = 1 << 1, + GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2, + GTK_FILE_FILTER_MIME_TYPE = 1 << 3 +} GtkFileFilterFlags; + +typedef enum { + GDK_COLORSPACE_RGB +} GdkColorspace; + +typedef enum { + GDK_INTERP_NEAREST, + GDK_INTERP_TILES, + GDK_INTERP_BILINEAR, + GDK_INTERP_HYPER +} GdkInterpType; + +typedef enum { + G_CONNECT_AFTER = 1 << 0, G_CONNECT_SWAPPED = 1 << 1 +} GConnectFlags; +//------------------------------ + + +typedef void GError; +typedef void GdkScreen; +typedef void GtkWindow; +typedef void GdkWindow; +typedef void GClosure; +typedef void GtkFileChooser; +typedef void GtkFileFilter; +typedef struct { + GtkFileFilterFlags contains; + const gchar *filename; + const gchar *uri; + const gchar *display_name; + const gchar *mime_type; +} GtkFileFilterInfo; +typedef gboolean (*GtkFileFilterFunc)(const GtkFileFilterInfo *filter_info, + gpointer data); +typedef void (*GClosureNotify)(gpointer data, GClosure *closure); +typedef void (*GDestroyNotify)(gpointer data); +typedef void (*GCallback)(void); + + +typedef struct GtkApi { + int version; + gboolean (*show_uri_load)(JNIEnv *env); + gboolean (*unload)(); + void (*flush_event_loop)(); + gchar* (*gtk_check_version)(guint required_major, guint required_minor, + guint required_micro); + jobject (*get_setting)(JNIEnv *env, Setting property); + + void (*paint_arrow)(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, + GtkArrowType arrow_type, gboolean fill); + void (*paint_box)(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, + gint synth_state, GtkTextDirection dir); + void (*paint_box_gap)(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, + GtkPositionType gap_side, gint gap_x, gint gap_width); + void (*paint_expander)(WidgetType widget_type, GtkStateType state_type, + const gchar *detail, gint x, gint y, gint width, gint height, + GtkExpanderStyle expander_style); + void (*paint_extension)(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, GtkPositionType gap_side); + void (*paint_flat_box)(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, gboolean has_focus); + void (*paint_focus)(WidgetType widget_type, GtkStateType state_type, + const char *detail, gint x, gint y, gint width, gint height); + void (*paint_handle)(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, GtkOrientation orientation); + void (*paint_hline)(WidgetType widget_type, GtkStateType state_type, + const gchar *detail, gint x, gint y, gint width, gint height); + void (*paint_vline)(WidgetType widget_type, GtkStateType state_type, + const gchar *detail, gint x, gint y, gint width, gint height); + void (*paint_option)(WidgetType widget_type, gint synth_state, + const gchar *detail, gint x, gint y, gint width, gint height); + void (*paint_shadow)(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, + gint synth_state, GtkTextDirection dir); + void (*paint_slider)(WidgetType widget_type, GtkStateType state_type, + GtkShadowType shadow_type, const gchar *detail, + gint x, gint y, gint width, gint height, GtkOrientation orientation, + gboolean has_focus); + void (*paint_background)(WidgetType widget_type, GtkStateType state_type, + gint x, gint y, gint width, gint height); + void (*paint_check)(WidgetType widget_type, gint synth_state, + const gchar *detail, gint x, gint y, gint width, gint height); + void (*set_range_value)(WidgetType widget_type, jdouble value, + jdouble min, jdouble max, jdouble visible); + + void (*init_painting)(JNIEnv *env, gint w, gint h); + gint (*copy_image)(gint *dest, gint width, gint height); + + gint (*get_xthickness)(JNIEnv *env, WidgetType widget_type); + gint (*get_ythickness)(JNIEnv *env, WidgetType widget_type); + gint (*get_color_for_state)(JNIEnv *env, WidgetType widget_type, + GtkStateType state_type, ColorType color_type); + jobject (*get_class_value)(JNIEnv *env, WidgetType widget_type, + const char* key); + + jstring (*get_pango_font_name)(JNIEnv *env, WidgetType widget_type); + jboolean (*get_icon_data)(JNIEnv *env, gint widget_type, + const gchar *stock_id, GtkIconSize size, + GtkTextDirection direction, const char *detail, + jmethodID icon_upcall_method, jobject this); + jboolean (*get_file_icon_data)(JNIEnv *env, const char *filename, + GError **error, jmethodID icon_upcall_method, jobject this); + void (*gdk_threads_enter)(void); + void (*gdk_threads_leave)(void); + gboolean (*gtk_show_uri)(GdkScreen *screen, const gchar *uri, + guint32 timestamp, GError **error); + gboolean (*get_drawable_data)(JNIEnv *env, jintArray pixelArray, + jint x, jint y, jint width, jint height, + jint jwidth, int dx, int dy, jint scale); + void (*g_free)(gpointer mem); + + + gchar* (*gtk_file_chooser_get_filename)(GtkFileChooser *chooser); + void (*gtk_widget_hide)(void* widget); + void (*gtk_main_quit)(void); + void* (*gtk_file_chooser_dialog_new)(const gchar *title, + GtkWindow *parent, GtkFileChooserAction action, + const gchar *first_button_text, ...); + gboolean (*gtk_file_chooser_set_current_folder)(GtkFileChooser *chooser, + const gchar *filename); + gboolean (*gtk_file_chooser_set_filename)(GtkFileChooser *chooser, + const char *filename); + void (*gtk_file_chooser_set_current_name)(GtkFileChooser *chooser, + const gchar *name); + void (*gtk_file_filter_add_custom)(GtkFileFilter *filter, + GtkFileFilterFlags needed, GtkFileFilterFunc func, gpointer data, + GDestroyNotify notify); + void (*gtk_file_chooser_set_filter)(GtkFileChooser *chooser, + GtkFileFilter *filter); + GType (*gtk_file_chooser_get_type)(void); + GtkFileFilter* (*gtk_file_filter_new)(void); + void (*gtk_file_chooser_set_do_overwrite_confirmation)( + GtkFileChooser *chooser, gboolean do_overwrite_confirmation); + void (*gtk_file_chooser_set_select_multiple)( + GtkFileChooser *chooser, gboolean select_multiple); + gchar* (*gtk_file_chooser_get_current_folder)(GtkFileChooser *chooser); + GSList* (*gtk_file_chooser_get_filenames)(GtkFileChooser *chooser); + guint (*gtk_g_slist_length)(GSList *list); + gulong (*g_signal_connect_data)(gpointer instance, + const gchar *detailed_signal, GCallback c_handler, gpointer data, + GClosureNotify destroy_data, GConnectFlags connect_flags); + void (*gtk_widget_show)(void *widget); + void (*gtk_main)(void); + guint (*gtk_main_level)(void); + gchar* (*g_path_get_dirname) (const gchar *file_name); + XID (*gdk_x11_drawable_get_xid) (void *drawable); + void (*gtk_widget_destroy)(void *widget); + void (*gtk_window_present)(void *window); + void (*gtk_window_move)(void *window, gint x, gint y); + void (*gtk_window_resize)(void *window, gint width, gint height); + GdkWindow *(*get_window)(void *widget); + + void (*g_object_unref)(gpointer object); + GList* (*g_list_append) (GList *list, gpointer data); + void (*g_list_free) (GList *list); + void (*g_list_free_full) (GList *list, GDestroyNotify free_func); +} GtkApi; + +gboolean gtk_load(JNIEnv *env, GtkVersion version, gboolean verbose); +gboolean gtk_check_version(GtkVersion version); + +extern GtkApi* gtk; + +#endif /* !_GTK_INTERFACE_H */ diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/sun_awt_X11_GtkFileDialogPeer.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/sun_awt_X11_GtkFileDialogPeer.c index 97fbcc60da0..556fe252538 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/sun_awt_X11_GtkFileDialogPeer.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/sun_awt_X11_GtkFileDialogPeer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,11 +28,12 @@ #include #include #include -#include "gtk2_interface.h" +#include "gtk_interface.h" #include "sun_awt_X11_GtkFileDialogPeer.h" #include "java_awt_FileDialog.h" #include "debug_assert.h" +typedef void GtkWidget; static JavaVM *jvm; /* To cache some method IDs */ @@ -90,20 +91,20 @@ static void quit(JNIEnv * env, jobject jpeer, gboolean isSignalHandler) { // 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() + // gdk_threads_enter() / gtk->gdk_threads_leave() if (!isSignalHandler) { - fp_gdk_threads_enter(); + gtk->gdk_threads_enter(); } - fp_gtk_widget_hide (dialog); - fp_gtk_widget_destroy (dialog); + gtk->gtk_widget_hide (dialog); + gtk->gtk_widget_destroy (dialog); - fp_gtk_main_quit (); + gtk->gtk_main_quit (); (*env)->SetLongField(env, jpeer, widgetFieldID, 0); if (!isSignalHandler) { - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } } @@ -133,16 +134,16 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_toFront { GtkWidget * dialog; - fp_gdk_threads_enter(); + gtk->gdk_threads_enter(); dialog = (GtkWidget*)jlong_to_ptr( (*env)->GetLongField(env, jpeer, widgetFieldID)); if (dialog != NULL) { - fp_gtk_window_present((GtkWindow*)dialog); + gtk->gtk_window_present((GtkWindow*)dialog); } - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -155,21 +156,21 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_setBounds { GtkWindow* dialog; - fp_gdk_threads_enter(); + gtk->gdk_threads_enter(); dialog = (GtkWindow*)jlong_to_ptr( (*env)->GetLongField(env, jpeer, widgetFieldID)); if (dialog != NULL) { if (x >= 0 && y >= 0) { - fp_gtk_window_move(dialog, (gint)x, (gint)y); + gtk->gtk_window_move(dialog, (gint)x, (gint)y); } if (width > 0 && height > 0) { - fp_gtk_window_resize(dialog, (gint)width, (gint)height); + gtk->gtk_window_resize(dialog, (gint)width, (gint)height); } } - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -182,18 +183,18 @@ static gboolean isFromSameDirectory(GSList* list, gchar** baseDir) { gboolean isAllDirsSame = TRUE; while (it) { - gchar* dir = fp_g_path_get_dirname((gchar*) it->data); + gchar* dir = gtk->g_path_get_dirname((gchar*) it->data); if (prevDir && strcmp(prevDir, dir) != 0) { isAllDirsSame = FALSE; - fp_g_free(dir); + gtk->g_free(dir); break; } if (!prevDir) { prevDir = strdup(dir); } - fp_g_free(dir); + gtk->g_free(dir); it = it->next; } @@ -233,7 +234,7 @@ static jobjectArray toFilenamesArray(JNIEnv *env, GSList* list, jstring* jcurren return NULL; } - array = (*env)->NewObjectArray(env, fp_gtk_g_slist_length(list), stringCls, NULL); + array = (*env)->NewObjectArray(env, gtk->gtk_g_slist_length(list), stringCls, NULL); if (array == NULL) { (*env)->ExceptionClear(env); JNU_ThrowInternalError(env, "Could not instantiate array files array"); @@ -287,7 +288,7 @@ static void handle_response(GtkWidget* aDialog, gint responseId, gpointer obj) filenames = NULL; if (responseId == GTK_RESPONSE_ACCEPT) { - filenames = fp_gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(aDialog)); + filenames = gtk->gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(aDialog)); } jfilenames = toFilenamesArray(env, filenames, &jcurrent_folder); @@ -318,7 +319,7 @@ Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer, JNU_CHECK_EXCEPTION(env); } - fp_gdk_threads_enter(); + gtk->gdk_threads_enter(); const char *title = jtitle == NULL? "": (*env)->GetStringUTFChars(env, jtitle, 0); if (title == NULL) { @@ -329,19 +330,19 @@ Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer, if (mode == java_awt_FileDialog_SAVE) { /* Save action */ - dialog = fp_gtk_file_chooser_dialog_new(title, NULL, + dialog = gtk->gtk_file_chooser_dialog_new(title, NULL, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); } else { /* Default action OPEN */ - dialog = fp_gtk_file_chooser_dialog_new(title, NULL, + dialog = gtk->gtk_file_chooser_dialog_new(title, NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); /* Set multiple selection mode, that is allowed only in OPEN action */ if (multiple) { - fp_gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), + gtk->gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), multiple); } } @@ -358,7 +359,7 @@ Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer, JNU_ThrowOutOfMemoryError(env, "Could not get dir"); return; } - fp_gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir); + gtk->gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir); (*env)->ReleaseStringUTFChars(env, jdir, dir); } @@ -371,47 +372,48 @@ Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer, return; } if (mode == java_awt_FileDialog_SAVE) { - fp_gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), filename); + gtk->gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), filename); } else { - fp_gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), filename); + gtk->gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), filename); } (*env)->ReleaseStringUTFChars(env, jfile, filename); } /* Set the file filter */ if (jfilter != NULL) { - filter = fp_gtk_file_filter_new(); - fp_gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME, + filter = gtk->gtk_file_filter_new(); + gtk->gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME, filenameFilterCallback, jpeer, NULL); - fp_gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter); + gtk->gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter); } /* Other Properties */ - if (fp_gtk_check_version(2, 8, 0) == NULL) { - fp_gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER( + if (gtk->gtk_check_version(2, 8, 0) == NULL || + gtk->gtk_check_version(3, 0, 0) == NULL) { + gtk->gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER( dialog), TRUE); } /* Set the initial location */ if (x >= 0 && y >= 0) { - fp_gtk_window_move((GtkWindow*)dialog, (gint)x, (gint)y); + gtk->gtk_window_move((GtkWindow*)dialog, (gint)x, (gint)y); // NOTE: it doesn't set the initial size for the file chooser // as it seems like the file chooser overrides the size internally } - fp_g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK( - handle_response), jpeer); + gtk->g_signal_connect_data(dialog, "response", G_CALLBACK( + handle_response), jpeer, 0, 0); (*env)->SetLongField(env, jpeer, widgetFieldID, ptr_to_jlong(dialog)); - fp_gtk_widget_show(dialog); + gtk->gtk_widget_show(dialog); - XID xid = fp_gdk_x11_drawable_get_xid(dialog->window); + XID xid = gtk->gdk_x11_drawable_get_xid(gtk->get_window(dialog)); if( (*env)->CallBooleanMethod(env, jpeer, setWindowMethodID, xid) ) { - fp_gtk_main(); + gtk->gtk_main(); } - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c index 7d9db4a5632..47c7ad23ebd 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * 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,9 +24,24 @@ */ #include -#include "gtk2_interface.h" +#include "gtk_interface.h" #include "com_sun_java_swing_plaf_gtk_GTKEngine.h" +/* Static buffer for conversion from java.lang.String to UTF-8 */ +static char conversionBuffer[CONV_BUFFER_SIZE]; + +const char *getStrFor(JNIEnv *env, jstring val) +{ + int length = (*env)->GetStringLength(env, val); + if (length > CONV_BUFFER_SIZE-1) + { + length = CONV_BUFFER_SIZE-1; + } + + (*env)->GetStringUTFRegion(env, val, 0, length, conversionBuffer); + return conversionBuffer; +} + /* * Class: com_sun_java_swing_plaf_gtk_GTKEngine * Method: native_paint_arrow @@ -38,10 +53,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1arrow( jint widget_type, jint state, jint shadow_type, jstring detail, jint x, jint y, jint w, jint h, jint arrow_type) { - fp_gdk_threads_enter(); - gtk2_paint_arrow(widget_type, state, shadow_type, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_arrow(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, arrow_type, TRUE); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -56,10 +71,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1box( jint x, jint y, jint w, jint h, jint synth_state, jint dir) { - fp_gdk_threads_enter(); - gtk2_paint_box(widget_type, state, shadow_type, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_box(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, synth_state, dir); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -74,10 +89,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1box_1gap( jint x, jint y, jint w, jint h, jint gap_side, jint gap_x, jint gap_w) { - fp_gdk_threads_enter(); - gtk2_paint_box_gap(widget_type, state, shadow_type, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_box_gap(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, gap_side, gap_x, gap_w); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -91,10 +106,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1check( jint widget_type, jint synth_state, jstring detail, jint x, jint y, jint w, jint h) { - fp_gdk_threads_enter(); - gtk2_paint_check(widget_type, synth_state, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_check(widget_type, synth_state, getStrFor(env, detail), x, y, w, h); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -108,10 +123,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1expander( jint widget_type, jint state, jstring detail, jint x, jint y, jint w, jint h, jint expander_style) { - fp_gdk_threads_enter(); - gtk2_paint_expander(widget_type, state, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_expander(widget_type, state, getStrFor(env, detail), x, y, w, h, expander_style); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -125,10 +140,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1extension( jint widget_type, jint state, jint shadow_type, jstring detail, jint x, jint y, jint w, jint h, jint placement) { - fp_gdk_threads_enter(); - gtk2_paint_extension(widget_type, state, shadow_type, + gtk->gdk_threads_enter(); + gtk->paint_extension(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, placement); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -142,10 +157,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1flat_1box( jint widget_type, jint state, jint shadow_type, jstring detail, jint x, jint y, jint w, jint h, jboolean has_focus) { - fp_gdk_threads_enter(); - gtk2_paint_flat_box(widget_type, state, shadow_type, + gtk->gdk_threads_enter(); + gtk->paint_flat_box(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, has_focus); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -159,10 +174,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1focus( jint widget_type, jint state, jstring detail, jint x, jint y, jint w, jint h) { - fp_gdk_threads_enter(); - gtk2_paint_focus(widget_type, state, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_focus(widget_type, state, getStrFor(env, detail), x, y, w, h); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -176,10 +191,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1handle( jint widget_type, jint state, jint shadow_type, jstring detail, jint x, jint y, jint w, jint h, jint orientation) { - fp_gdk_threads_enter(); - gtk2_paint_handle(widget_type, state, shadow_type, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_handle(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, orientation); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -193,10 +208,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1hline( jint widget_type, jint state, jstring detail, jint x, jint y, jint w, jint h) { - fp_gdk_threads_enter(); - gtk2_paint_hline(widget_type, state, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_hline(widget_type, state, getStrFor(env, detail), x, y, w, h); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -210,10 +225,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1option( jint widget_type, jint synth_state, jstring detail, jint x, jint y, jint w, jint h) { - fp_gdk_threads_enter(); - gtk2_paint_option(widget_type, synth_state, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_option(widget_type, synth_state, getStrFor(env, detail), x, y, w, h); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -228,10 +243,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1shadow( jint x, jint y, jint w, jint h, jint synth_state, jint dir) { - fp_gdk_threads_enter(); - gtk2_paint_shadow(widget_type, state, shadow_type, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_shadow(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, synth_state, dir); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -243,12 +258,12 @@ JNIEXPORT void JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1slider( JNIEnv *env, jobject this, jint widget_type, jint state, jint shadow_type, jstring detail, - jint x, jint y, jint w, jint h, jint orientation) + jint x, jint y, jint w, jint h, jint orientation, jboolean has_focus) { - fp_gdk_threads_enter(); - gtk2_paint_slider(widget_type, state, shadow_type, getStrFor(env, detail), - x, y, w, h, orientation); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + gtk->paint_slider(widget_type, state, shadow_type, getStrFor(env, detail), + x, y, w, h, orientation, has_focus); + gtk->gdk_threads_leave(); } /* @@ -262,10 +277,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1vline( jint widget_type, jint state, jstring detail, jint x, jint y, jint w, jint h) { - fp_gdk_threads_enter(); - gtk2_paint_vline(widget_type, state, getStrFor(env, detail), + gtk->gdk_threads_enter(); + gtk->paint_vline(widget_type, state, getStrFor(env, detail), x, y, w, h); - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -278,9 +293,9 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1background( JNIEnv *env, jobject this, jint widget_type, jint state, jint x, jint y, jint w, jint h) { - fp_gdk_threads_enter(); - gtk_paint_background(widget_type, state, x, y, w, h); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + gtk->paint_background(widget_type, state, x, y, w, h); + gtk->gdk_threads_leave(); } /* @@ -292,9 +307,9 @@ JNIEXPORT void JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeStartPainting( JNIEnv *env, jobject this, jint w, jint h) { - fp_gdk_threads_enter(); - gtk2_init_painting(env, w, h); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + gtk->init_painting(env, w, h); + gtk->gdk_threads_leave(); } /* @@ -308,9 +323,9 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeFinishPainting( { jint transparency; gint *buffer = (gint*) (*env)->GetPrimitiveArrayCritical(env, dest, 0); - fp_gdk_threads_enter(); - transparency = gtk2_copy_image(buffer, width, height); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + transparency = gtk->copy_image(buffer, width, height); + gtk->gdk_threads_leave(); (*env)->ReleasePrimitiveArrayCritical(env, dest, buffer, 0); return transparency; } @@ -324,7 +339,9 @@ JNIEXPORT void JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1switch JNIEnv *env, jobject this) { // Note that flush_gtk_event_loop takes care of locks (7053002) - flush_gtk_event_loop(); + gtk->gdk_threads_enter(); + gtk->flush_event_loop(); + gtk->gdk_threads_leave(); } /* @@ -336,9 +353,9 @@ JNIEXPORT jobject JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1get JNIEnv *env, jobject this, jint property) { jobject obj; - fp_gdk_threads_enter(); - obj = gtk2_get_setting(env, property); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + obj = gtk->get_setting(env, property); + gtk->gdk_threads_leave(); return obj; } @@ -352,7 +369,7 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeSetRangeValue( JNIEnv *env, jobject this, jint widget_type, jdouble value, jdouble min, jdouble max, jdouble visible) { - fp_gdk_threads_enter(); - gtk2_set_range_value(widget_type, value, min, max, visible); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + gtk->set_range_value(widget_type, value, min, max, visible); + gtk->gdk_threads_leave(); } diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKStyle.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKStyle.c index 9d24eb44973..a977f6bee2e 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKStyle.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKStyle.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * 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,9 +24,12 @@ */ #include -#include "gtk2_interface.h" +#include +#include "gtk_interface.h" #include "com_sun_java_swing_plaf_gtk_GTKStyle.h" +const char *getStrFor(JNIEnv *env, jstring val); + /* * Class: com_sun_java_swing_plaf_gtk_GTKStyle * Method: nativeGetXThickness @@ -37,9 +40,9 @@ Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetXThickness( JNIEnv *env, jclass klass, jint widget_type) { jint ret; - fp_gdk_threads_enter(); - ret = gtk2_get_xthickness(env, widget_type); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + ret = gtk->get_xthickness(env, widget_type); + gtk->gdk_threads_leave(); return ret; } @@ -53,9 +56,9 @@ Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetYThickness( JNIEnv *env, jclass klass, jint widget_type) { jint ret; - fp_gdk_threads_enter(); - ret = gtk2_get_ythickness(env, widget_type); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + ret = gtk->get_ythickness(env, widget_type); + gtk->gdk_threads_leave(); return ret; } @@ -70,9 +73,9 @@ Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetColorForState( jint state_type, jint type_id) { jint ret; - fp_gdk_threads_enter(); - ret = gtk2_get_color_for_state(env, widget_type, state_type, type_id); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + ret = gtk->get_color_for_state(env, widget_type, state_type, type_id); + gtk->gdk_threads_leave(); return ret; } @@ -86,9 +89,9 @@ Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetClassValue( JNIEnv *env, jclass klass, jint widget_type, jstring key) { jobject ret; - fp_gdk_threads_enter(); - ret = gtk2_get_class_value(env, widget_type, key); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + ret = gtk->get_class_value(env, widget_type, getStrFor(env, key)); + gtk->gdk_threads_leave(); return ret; } @@ -102,8 +105,8 @@ Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetPangoFontName( JNIEnv *env, jclass klass, jint widget_type) { jstring ret; - fp_gdk_threads_enter(); - ret = gtk2_get_pango_font_name(env, widget_type); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + ret = gtk->get_pango_font_name(env, widget_type); + gtk->gdk_threads_leave(); return ret; } diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Desktop.c b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Desktop.c index 0c41daee3ab..96acfb59d11 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Desktop.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Desktop.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ */ #include "jni_util.h" -#include "gtk2_interface.h" +#include "gtk_interface.h" #include "gnome_interface.h" static gboolean gtk_has_been_loaded = FALSE; @@ -36,14 +36,14 @@ static gboolean gnome_has_been_loaded = FALSE; * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XDesktopPeer_init - (JNIEnv *env, jclass cls) + (JNIEnv *env, jclass cls, jint version, jboolean verbose) { if (gtk_has_been_loaded || gnome_has_been_loaded) { return JNI_TRUE; } - if (gtk2_load(env) && gtk2_show_uri_load(env)) { + if (gtk_load(env, version, verbose) && gtk->show_uri_load(env)) { gtk_has_been_loaded = TRUE; return JNI_TRUE; } else if (gnome_load()) { @@ -74,9 +74,9 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XDesktopPeer_gnome_1url_1show } if (gtk_has_been_loaded) { - fp_gdk_threads_enter(); - success = fp_gtk_show_uri(NULL, url_c, GDK_CURRENT_TIME, NULL); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + success = gtk->gtk_show_uri(NULL, url_c, GDK_CURRENT_TIME, NULL); + gtk->gdk_threads_leave(); } else if (gnome_has_been_loaded) { success = (*gnome_url_show)(url_c, NULL); } diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c index 643cc888b51..210f2de4da4 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c @@ -109,7 +109,7 @@ void callback(DbusmenuMenuitem* mi, guint ts, jobject data) { * Signature: (Ljava/lang/String;)Z */ JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XTaskbarPeer_init -(JNIEnv *env, jclass cls, jstring jname) { +(JNIEnv *env, jclass cls, jstring jname, jint version, jboolean verbose) { jclass clazz; jTaskbarCls = (*env)->NewGlobalRef(env, cls); @@ -121,7 +121,7 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XTaskbarPeer_init CHECK_NULL_RETURN( jMenuItemGetLabel = (*env)->GetMethodID(env, clazz, "getLabel", "()Ljava/lang/String;"), JNI_FALSE); - if (gtk2_load(env) && unity_load()) { + if (gtk_load(env, version, verbose) && unity_load()) { const gchar* name = (*env)->GetStringUTFChars(env, jname, NULL); if (name) { entry = fp_unity_launcher_entry_get_for_desktop_file(name); @@ -139,9 +139,9 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XTaskbarPeer_init */ JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_runloop (JNIEnv *env, jclass cls) { - fp_gdk_threads_enter(); - fp_gtk_main(); - fp_gdk_threads_leave(); + gtk->gdk_threads_enter(); + gtk->gtk_main(); + gtk->gdk_threads_leave(); } /* @@ -151,14 +151,14 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_runloop */ JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_setBadge (JNIEnv *env, jobject obj, jlong value, jboolean visible) { - fp_gdk_threads_enter(); + gtk->gdk_threads_enter(); fp_unity_launcher_entry_set_count(entry, value); fp_unity_launcher_entry_set_count_visible(entry, visible); DbusmenuMenuitem* m; if (m = fp_unity_launcher_entry_get_quicklist(entry)) { fp_unity_launcher_entry_set_quicklist(entry, m); } - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -168,13 +168,13 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_setBadge */ JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_setUrgent (JNIEnv *env, jobject obj, jboolean urgent) { - fp_gdk_threads_enter(); + gtk->gdk_threads_enter(); fp_unity_launcher_entry_set_urgent(entry, urgent); DbusmenuMenuitem* m; if (m = fp_unity_launcher_entry_get_quicklist(entry)) { fp_unity_launcher_entry_set_quicklist(entry, m); } - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } /* @@ -184,14 +184,14 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_setUrgent */ JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_updateProgress (JNIEnv *env, jobject obj, jdouble value, jboolean visible) { - fp_gdk_threads_enter(); + gtk->gdk_threads_enter(); fp_unity_launcher_entry_set_progress(entry, value); fp_unity_launcher_entry_set_progress_visible(entry, visible); DbusmenuMenuitem* m; if (m = fp_unity_launcher_entry_get_quicklist(entry)) { fp_unity_launcher_entry_set_quicklist(entry, m); } - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } void deleteGlobalRef(gpointer data) { @@ -209,7 +209,7 @@ void fill_menu(JNIEnv *env, jobjectArray items) { } elem = (*env)->NewGlobalRef(env, elem); - globalRefs = fp_g_list_append(globalRefs, elem); + globalRefs = gtk->g_list_append(globalRefs, elem); jstring jlabel = (jstring) (*env)->CallObjectMethod(env, elem, jMenuItemGetLabel); if (!(*env)->ExceptionCheck(env) && jlabel) { @@ -224,7 +224,8 @@ void fill_menu(JNIEnv *env, jobjectArray items) { (*env)->ReleaseStringUTFChars(env, jlabel, label); fp_dbusmenu_menuitem_child_append(menu, mi); - fp_g_signal_connect(mi, "item_activated", G_CALLBACK(callback), elem); + gtk->g_signal_connect_data(mi, "item_activated", + G_CALLBACK(callback), elem, NULL, 0); } } } @@ -238,7 +239,7 @@ void fill_menu(JNIEnv *env, jobjectArray items) { JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_setNativeMenu (JNIEnv *env, jobject obj, jobjectArray items) { - fp_gdk_threads_enter(); + gtk->gdk_threads_enter(); if (!menu) { menu = fp_dbusmenu_menuitem_new(); @@ -247,14 +248,14 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_setNativeMenu fp_unity_launcher_entry_set_quicklist(entry, menu); GList* list = fp_dbusmenu_menuitem_take_children(menu); - fp_g_list_free_full(list, fp_g_object_unref); + gtk->g_list_free_full(list, gtk->g_object_unref); - fp_g_list_free_full(globalRefs, deleteGlobalRef); + gtk->g_list_free_full(globalRefs, deleteGlobalRef); globalRefs = NULL; if (items) { fill_menu(env, items); } - fp_gdk_threads_leave(); + gtk->gdk_threads_leave(); } diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.h b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.h index 00b8d86dd1f..5baffd8e444 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.h +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.h @@ -26,7 +26,7 @@ #ifndef AWT_TASKBAR_H #define AWT_TASKBAR_H -#include "gtk2_interface.h" +#include "gtk_interface.h" typedef void UnityLauncherEntry; typedef void DbusmenuMenuitem; diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/gnome_interface.h b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/gnome_interface.h index 2ca444725e8..bfd764364d7 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/gnome_interface.h +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/gnome_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ #ifndef _GNOME_INTERFACE_H #define _GNOME_INTERFACE_H -#include "gtk2_interface.h" +#include "gtk_interface.h" #include #include #include From f4d962e735d90915da9095586b29f2bf671b92e8 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 25 Apr 2016 09:57:55 -0300 Subject: [PATCH 134/222] 8147426: Missing definition for JIMAGE_NOT_FOUND Reviewed-by: hseigel, alanb --- jdk/src/java.base/share/native/libjimage/jimage.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/native/libjimage/jimage.hpp b/jdk/src/java.base/share/native/libjimage/jimage.hpp index d215e30c2ab..f3371204ec7 100644 --- a/jdk/src/java.base/share/native/libjimage/jimage.hpp +++ b/jdk/src/java.base/share/native/libjimage/jimage.hpp @@ -37,11 +37,13 @@ class JImageFile; typedef jlong JImageLocationRef; // Max path length limit independent of platform. Windows max path is 1024, -// other platforms use 4096. The JCK fails several tests when 1024 is used. +// other platforms use 4096. #define JIMAGE_MAX_PATH 4096 // JImage Error Codes +// Resource was not found +#define JIMAGE_NOT_FOUND (0) // The image file is not prefixed with 0xCAFEDADA #define JIMAGE_BAD_MAGIC (-1) // The image file does not have a compatible (translatable) version From 5013b6458071350c568b81cd57bf4ed25b4839ae Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 25 Apr 2016 09:57:55 -0300 Subject: [PATCH 135/222] 8147634: Need a JImage API that given a JImageLocationRef returns class name Reviewed-by: hseigel --- jdk/make/lib/CoreLibraries.gmk | 2 +- jdk/make/mapfiles/libjimage/mapfile-vers | 1 + .../share/native/libjimage/jimage.cpp | 25 ++++++++++++++++++- .../share/native/libjimage/jimage.hpp | 17 +++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk index e4a24e47904..3cb135253ea 100644 --- a/jdk/make/lib/CoreLibraries.gmk +++ b/jdk/make/lib/CoreLibraries.gmk @@ -267,7 +267,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJIMAGE, \ LDFLAGS_windows := -export:JIMAGE_Open -export:JIMAGE_Close \ -export:JIMAGE_PackageToModule \ -export:JIMAGE_FindResource -export:JIMAGE_GetResource \ - -export:JIMAGE_ResourceIterator, \ + -export:JIMAGE_ResourceIterator -export:JIMAGE_ResourcePath, \ LIBS_unix := -ljvm -ldl $(LIBCXX), \ LIBS_solaris := -lc, \ LIBS_macosx := -lc++, \ diff --git a/jdk/make/mapfiles/libjimage/mapfile-vers b/jdk/make/mapfiles/libjimage/mapfile-vers index 48eac21b53a..a4de5f82f3c 100644 --- a/jdk/make/mapfiles/libjimage/mapfile-vers +++ b/jdk/make/mapfiles/libjimage/mapfile-vers @@ -34,6 +34,7 @@ SUNWprivate_1.1 { JIMAGE_FindResource; JIMAGE_GetResource; JIMAGE_ResourceIterator; + JIMAGE_ResourcePath; local: *; }; diff --git a/jdk/src/java.base/share/native/libjimage/jimage.cpp b/jdk/src/java.base/share/native/libjimage/jimage.cpp index 4816a173be9..0c12facbc4d 100644 --- a/jdk/src/java.base/share/native/libjimage/jimage.cpp +++ b/jdk/src/java.base/share/native/libjimage/jimage.cpp @@ -207,7 +207,30 @@ extern "C" void JIMAGE_ResourceIterator(JImageFile* image, if (!(*visitor)(image, module, "9", parent, base, extension, arg)) { break; } - } } +/* + * JIMAGE_ResourcePath- Given an open image file, a location reference, a buffer + * and a maximum buffer size, copy the path of the resource into the buffer. + * Returns false if not a valid location reference. + * + * Ex. + * JImageLocationRef location = ... + * char path[JIMAGE_MAX_PATH]; + * (*JImageResourcePath)(image, location, path, JIMAGE_MAX_PATH); + */ +extern "C" bool JIMAGE_ResourcePath(JImageFile* image, JImageLocationRef locationRef, + char* path, size_t max) { + ImageFileReader* imageFile = (ImageFileReader*) image; + + u4 offset = (u4) locationRef; + if (offset >= imageFile->locations_size()) { + return false; + } + + ImageLocation location(imageFile->get_location_offset_data(offset)); + imageFile->location_path(location, path, max); + + return true; +} diff --git a/jdk/src/java.base/share/native/libjimage/jimage.hpp b/jdk/src/java.base/share/native/libjimage/jimage.hpp index f3371204ec7..637f1689e49 100644 --- a/jdk/src/java.base/share/native/libjimage/jimage.hpp +++ b/jdk/src/java.base/share/native/libjimage/jimage.hpp @@ -186,3 +186,20 @@ extern "C" void JIMAGE_ResourceIterator(JImageFile* jimage, typedef void (*JImageResourceIterator_t)(JImageFile* jimage, JImageResourceVisitor_t visitor, void* arg); + +/* + * JIMAGE_ResourcePath- Given an open image file, a location reference, a buffer + * and a maximum buffer size, copy the path of the resource into the buffer. + * Returns false if not a valid location reference. + * + * Ex. + * JImageLocationRef location = ... + * char path[JIMAGE_MAX_PATH]; + * (*JImageResourcePath)(image, location, path, JIMAGE_MAX_PATH); + */ +extern "C" bool JIMAGE_ResourcePath(JImageFile* image, JImageLocationRef locationRef, + char* path, size_t max); + +typedef bool (*JImage_ResourcePath_t)(JImageFile* jimage, JImageLocationRef location, + char* buffer, jlong size); + From 80b4b623c7b292ca84e8795f37a0f26f37ad8f13 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 25 Apr 2016 09:57:55 -0300 Subject: [PATCH 136/222] 8082537: jimage should print usage when started with no args Reviewed-by: alanb --- .../jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java index 44a6bcc4ce3..105e8f61b44 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java @@ -152,6 +152,11 @@ class JImageTask { setLog(new PrintWriter(System.out)); } + if (args.length == 0) { + log.println(taskHelper.getMessage("main.usage.summary", PROGNAME)); + return EXIT_ABNORMAL; + } + try { List unhandled = optionsHelper.handleOptions(this, args); if(!unhandled.isEmpty()) { From 58b1ba941edb7bbc991194e2d4b660e0f49964b3 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 25 Apr 2016 09:57:55 -0300 Subject: [PATCH 137/222] 8153930: Compiler crashed (intermittently) Reviewed-by: redestad, alanb --- .../jdk/internal/jimage/ImageReader.java | 829 ++++++++++-------- .../jdk/internal/jrtfs/JrtFileSystem.java | 12 +- .../jdk/internal/jrtfs/SystemImage.java | 4 +- 3 files changed, 479 insertions(+), 366 deletions(-) diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java index 41a51b88acf..2c78ea9e5d5 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java @@ -25,6 +25,7 @@ package jdk.internal.jimage; import java.io.IOException; +import java.io.InputStream; import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -36,8 +37,11 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; /** @@ -47,80 +51,486 @@ import java.util.function.Consumer; * but also compiled and delivered as part of the jrtfs.jar to support access * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ -public class ImageReader extends BasicImageReader { +public final class ImageReader implements AutoCloseable { + private SharedImageReader reader; - private static final int SIZE_OF_OFFSET = 4; - - // Map of files opened as LITTLE_ENDIAN - private static final HashMap OPEN_LE_FILES - = new HashMap<>(); - - // Map of files opened as BIG_ENDIAN - private static final HashMap OPEN_BE_FILES - = new HashMap<>(); - - private int openCount; - - // attributes of the .jimage file. jimage file does not contain - // attributes for the individual resources (yet). We use attributes - // of the jimage file itself (creation, modification, access times). - // Iniitalized lazily, see {@link #imageFileAttributes()}. - private BasicFileAttributes imageFileAttributes; - - // directory management implementation - private final HashMap nodes; - private volatile Directory rootDir; - - private Directory packagesDir; - private Directory modulesDir; - - private ImageReader(Path imagePath, ByteOrder byteOrder) throws IOException { - super(imagePath, byteOrder); - this.nodes = new HashMap<>(); + private ImageReader(SharedImageReader reader) { + this.reader = reader; } public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException { - HashMap openFiles = getOpenFilesMap(byteOrder); - ImageReader reader; - synchronized (openFiles) { - reader = openFiles.get(imagePath); - if (reader == null) { - reader = new ImageReader(imagePath, byteOrder); - ImageReader existingReader = openFiles.putIfAbsent(imagePath, reader); - assert (existingReader == null); - } - reader.openCount++; - } - return reader; + return SharedImageReader.open(imagePath, byteOrder); } - private static HashMap getOpenFilesMap(ByteOrder byteOrder) { - return (byteOrder == ByteOrder.BIG_ENDIAN) ? OPEN_BE_FILES : OPEN_LE_FILES; - } - - /** - * Opens the given file path as an image file, returning an {@code ImageReader}. - */ public static ImageReader open(Path imagePath) throws IOException { return open(imagePath, ByteOrder.nativeOrder()); } - private boolean canClose() { - HashMap openFiles = getOpenFilesMap(this.getByteOrder()); - synchronized (openFiles) { - if (--this.openCount == 0) { - return openFiles.remove(this.getName(), this); - } - } - return false; - } - @Override public void close() throws IOException { - if (canClose()) { - super.close(); - clearNodes(); - } + if (reader == null) { + throw new IOException("image file already closed"); + } + + reader.close(this); + reader = null; + } + + // directory management interface + public Directory getRootDirectory() throws IOException { + if (reader == null) { + throw new IOException("image file closed"); + } + return reader.getRootDirectory(); + } + + public Node findNode(String name) throws IOException { + if (reader == null) { + throw new IOException("image file closed"); + } + return reader.findNode(name); + } + + public byte[] getResource(Node node) throws IOException { + if (reader == null) { + throw new IOException("image file closed"); + } + return reader.getResource(node); + } + + public byte[] getResource(Resource rs) throws IOException { + if (reader == null) { + throw new IOException("image file closed"); + } + return reader.getResource(rs); + } + + public ImageHeader getHeader() { + Objects.requireNonNull(reader, "image file closed"); + return reader.getHeader(); + } + + public static void releaseByteBuffer(ByteBuffer buffer) { + BasicImageReader.releaseByteBuffer(buffer); + } + + public String getName() { + Objects.requireNonNull(reader, "image file closed"); + return reader.getName() ; + } + + public ByteOrder getByteOrder() { + Objects.requireNonNull(reader, "image file closed"); + return reader.getByteOrder(); + } + + public Path getImagePath() { + Objects.requireNonNull(reader, "image file closed"); + return reader.getImagePath(); + } + + public ImageStringsReader getStrings() { + Objects.requireNonNull(reader, "image file closed"); + return reader.getStrings(); + } + + public ImageLocation findLocation(String mn, String rn) { + Objects.requireNonNull(reader, "image file closed"); + return reader.findLocation(mn, rn); + } + + public ImageLocation findLocation(String name) { + Objects.requireNonNull(reader, "image file closed"); + return reader.findLocation(name); + } + + public String[] getEntryNames() { + Objects.requireNonNull(reader, "image file closed"); + return reader.getEntryNames(); + } + + public long[] getAttributes(int offset) { + Objects.requireNonNull(reader, "image file closed"); + return reader.getAttributes(offset); + } + + public String getString(int offset) { + Objects.requireNonNull(reader, "image file closed"); + return reader.getString(offset); + } + + public byte[] getResource(String name) { + Objects.requireNonNull(reader, "image file closed"); + return reader.getResource(name); + } + + public byte[] getResource(ImageLocation loc) { + Objects.requireNonNull(reader, "image file closed"); + return reader.getResource(loc); + } + + public ByteBuffer getResourceBuffer(ImageLocation loc) { + Objects.requireNonNull(reader, "image file closed"); + return reader.getResourceBuffer(loc); + } + + public InputStream getResourceStream(ImageLocation loc) { + Objects.requireNonNull(reader, "image file closed"); + return reader.getResourceStream(loc); + } + + private final static class SharedImageReader extends BasicImageReader { + static final int SIZE_OF_OFFSET = Integer.BYTES; + + static final Map OPEN_FILES = new HashMap<>(); + + // List of openers for this shared image. + final Set openers; + + // attributes of the .jimage file. jimage file does not contain + // attributes for the individual resources (yet). We use attributes + // of the jimage file itself (creation, modification, access times). + // Iniitalized lazily, see {@link #imageFileAttributes()}. + BasicFileAttributes imageFileAttributes; + + // directory management implementation + final HashMap nodes; + volatile Directory rootDir; + + Directory packagesDir; + Directory modulesDir; + + private SharedImageReader(Path imagePath, ByteOrder byteOrder) throws IOException { + super(imagePath, byteOrder); + this.openers = new HashSet<>(); + this.nodes = new HashMap<>(); + } + + public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException { + synchronized (OPEN_FILES) { + SharedImageReader reader = OPEN_FILES.get(imagePath); + + if (reader == null) { + // Will fail with an IOException if wrong byteOrder. + reader = new SharedImageReader(imagePath, byteOrder); + OPEN_FILES.put(imagePath, reader); + } else if (reader.getByteOrder() != byteOrder) { + throw new IOException("\"" + reader.getName() + "\" is not an image file"); + } + + ImageReader image = new ImageReader(reader); + reader.openers.add(image); + + return image; + } + } + + public void close(ImageReader image) throws IOException { + synchronized (OPEN_FILES) { + if (!openers.remove(image)) { + throw new IOException("image file already closed"); + } + + if (openers.isEmpty()) { + close(); + nodes.clear(); + rootDir = null; + + if (!OPEN_FILES.remove(this.getImagePath(), this)) { + throw new IOException("image file not found in open list"); + } + } + } + } + + void addOpener(ImageReader reader) { + synchronized (OPEN_FILES) { + openers.add(reader); + } + } + + boolean removeOpener(ImageReader reader) { + synchronized (OPEN_FILES) { + return openers.remove(reader); + } + } + + // directory management interface + Directory getRootDirectory() { + return buildRootDirectory(); + } + + /** + * Lazily build a node from a name. + */ + synchronized Node buildNode(String name) { + Node n; + boolean isPackages = name.startsWith("/packages"); + boolean isModules = !isPackages && name.startsWith("/modules"); + + if (!(isModules || isPackages)) { + return null; + } + + ImageLocation loc = findLocation(name); + + if (loc != null) { // A sub tree node + if (isPackages) { + n = handlePackages(name, loc); + } else { // modules sub tree + n = handleModulesSubTree(name, loc); + } + } else { // Asking for a resource? /modules/java.base/java/lang/Object.class + if (isModules) { + n = handleResource(name); + } else { + // Possibly ask for /packages/java.lang/java.base + // although /packages/java.base not created + n = handleModuleLink(name); + } + } + return n; + } + + synchronized Directory buildRootDirectory() { + Directory root = rootDir; // volatile read + if (root != null) { + return root; + } + + root = newDirectory(null, "/"); + root.setIsRootDir(); + + // /packages dir + packagesDir = newDirectory(root, "/packages"); + packagesDir.setIsPackagesDir(); + + // /modules dir + modulesDir = newDirectory(root, "/modules"); + modulesDir.setIsModulesDir(); + + root.setCompleted(true); + return rootDir = root; + } + + /** + * To visit sub tree resources. + */ + interface LocationVisitor { + void visit(ImageLocation loc); + } + + void visitLocation(ImageLocation loc, LocationVisitor visitor) { + byte[] offsets = getResource(loc); + ByteBuffer buffer = ByteBuffer.wrap(offsets); + buffer.order(getByteOrder()); + IntBuffer intBuffer = buffer.asIntBuffer(); + for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) { + int offset = intBuffer.get(i); + ImageLocation pkgLoc = getLocation(offset); + visitor.visit(pkgLoc); + } + } + + void visitPackageLocation(ImageLocation loc) { + // Retrieve package name + String pkgName = getBaseExt(loc); + // Content is array of offsets in Strings table + byte[] stringsOffsets = getResource(loc); + ByteBuffer buffer = ByteBuffer.wrap(stringsOffsets); + buffer.order(getByteOrder()); + IntBuffer intBuffer = buffer.asIntBuffer(); + // For each module, create a link node. + for (int i = 0; i < stringsOffsets.length / SIZE_OF_OFFSET; i++) { + // skip empty state, useless. + intBuffer.get(i); + i++; + int offset = intBuffer.get(i); + String moduleName = getString(offset); + Node targetNode = findNode("/modules/" + moduleName); + if (targetNode != null) { + String pkgDirName = packagesDir.getName() + "/" + pkgName; + Directory pkgDir = (Directory) nodes.get(pkgDirName); + newLinkNode(pkgDir, pkgDir.getName() + "/" + moduleName, targetNode); + } + } + } + + Node handlePackages(String name, ImageLocation loc) { + long size = loc.getUncompressedSize(); + Node n = null; + // Only possiblities are /packages, /packages/package/module + if (name.equals("/packages")) { + visitLocation(loc, (childloc) -> { + findNode(childloc.getFullName()); + }); + packagesDir.setCompleted(true); + n = packagesDir; + } else { + if (size != 0) { // children are offsets to module in StringsTable + String pkgName = getBaseExt(loc); + Directory pkgDir = newDirectory(packagesDir, packagesDir.getName() + "/" + pkgName); + visitPackageLocation(loc); + pkgDir.setCompleted(true); + n = pkgDir; + } else { // Link to module + String pkgName = loc.getParent(); + String modName = getBaseExt(loc); + Node targetNode = findNode("/modules/" + modName); + if (targetNode != null) { + String pkgDirName = packagesDir.getName() + "/" + pkgName; + Directory pkgDir = (Directory) nodes.get(pkgDirName); + Node linkNode = newLinkNode(pkgDir, pkgDir.getName() + "/" + modName, targetNode); + n = linkNode; + } + } + } + return n; + } + + // Asking for /packages/package/module although + // /packages// not yet created, need to create it + // prior to return the link to module node. + Node handleModuleLink(String name) { + // eg: unresolved /packages/package/module + // Build /packages/package node + Node ret = null; + String radical = "/packages/"; + String path = name; + if (path.startsWith(radical)) { + int start = radical.length(); + int pkgEnd = path.indexOf('/', start); + if (pkgEnd != -1) { + String pkg = path.substring(start, pkgEnd); + String pkgPath = radical + pkg; + Node n = findNode(pkgPath); + // If not found means that this is a symbolic link such as: + // /packages/java.util/java.base/java/util/Vector.class + // and will be done by a retry of the filesystem + for (Node child : n.getChildren()) { + if (child.name.equals(name)) { + ret = child; + break; + } + } + } + } + return ret; + } + + Node handleModulesSubTree(String name, ImageLocation loc) { + Node n; + assert (name.equals(loc.getFullName())); + Directory dir = makeDirectories(name); + visitLocation(loc, (childloc) -> { + String path = childloc.getFullName(); + if (path.startsWith("/modules")) { // a package + makeDirectories(path); + } else { // a resource + makeDirectories(childloc.buildName(true, true, false)); + newResource(dir, childloc); + } + }); + dir.setCompleted(true); + n = dir; + return n; + } + + Node handleResource(String name) { + Node n = null; + String locationPath = name.substring("/modules".length()); + ImageLocation resourceLoc = findLocation(locationPath); + if (resourceLoc != null) { + Directory dir = makeDirectories(resourceLoc.buildName(true, true, false)); + Resource res = newResource(dir, resourceLoc); + n = res; + } + return n; + } + + String getBaseExt(ImageLocation loc) { + String base = loc.getBase(); + String ext = loc.getExtension(); + if (ext != null && !ext.isEmpty()) { + base = base + "." + ext; + } + return base; + } + + synchronized Node findNode(String name) { + buildRootDirectory(); + Node n = nodes.get(name); + if (n == null || !n.isCompleted()) { + n = buildNode(name); + } + return n; + } + + /** + * Returns the file attributes of the image file. + */ + BasicFileAttributes imageFileAttributes() { + BasicFileAttributes attrs = imageFileAttributes; + if (attrs == null) { + try { + Path file = getImagePath(); + attrs = Files.readAttributes(file, BasicFileAttributes.class); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + imageFileAttributes = attrs; + } + return attrs; + } + + Directory newDirectory(Directory parent, String name) { + Directory dir = Directory.create(parent, name, imageFileAttributes()); + nodes.put(dir.getName(), dir); + return dir; + } + + Resource newResource(Directory parent, ImageLocation loc) { + Resource res = Resource.create(parent, loc, imageFileAttributes()); + nodes.put(res.getName(), res); + return res; + } + + LinkNode newLinkNode(Directory dir, String name, Node link) { + LinkNode linkNode = LinkNode.create(dir, name, link); + nodes.put(linkNode.getName(), linkNode); + return linkNode; + } + + Directory makeDirectories(String parent) { + Directory last = rootDir; + for (int offset = parent.indexOf('/', 1); + offset != -1; + offset = parent.indexOf('/', offset + 1)) { + String dir = parent.substring(0, offset); + last = makeDirectory(dir, last); + } + return makeDirectory(parent, last); + + } + + Directory makeDirectory(String dir, Directory last) { + Directory nextDir = (Directory) nodes.get(dir); + if (nextDir == null) { + nextDir = newDirectory(last, dir); + } + return nextDir; + } + + byte[] getResource(Node node) throws IOException { + if (node.isResource()) { + return super.getResource(node.getLocation()); + } + throw new IOException("Not a resource: " + node); + } + + byte[] getResource(Resource rs) throws IOException { + return super.getResource(rs.getLocation()); + } } // jimage file does not store directory structure. We build nodes @@ -389,7 +799,7 @@ public class ImageReader extends BasicImageReader { @Override public Node resolveLink(boolean recursive) { - return recursive && (link instanceof LinkNode)? ((LinkNode)link).resolveLink(true) : link; + return (recursive && link instanceof LinkNode) ? ((LinkNode)link).resolveLink(true) : link; } @Override @@ -397,297 +807,4 @@ public class ImageReader extends BasicImageReader { return true; } } - - // directory management interface - public Directory getRootDirectory() { - return buildRootDirectory(); - } - - /** - * To visit sub tree resources. - */ - interface LocationVisitor { - - void visit(ImageLocation loc); - } - - /** - * Lazily build a node from a name. - */ - private Node buildNode(String name) { - Node n; - boolean isPackages = name.startsWith("/packages"); - boolean isModules = !isPackages && name.startsWith("/modules"); - - if (!(isModules || isPackages)) { - return null; - } - - ImageLocation loc = findLocation(name); - - if (loc != null) { // A sub tree node - if (isPackages) { - n = handlePackages(name, loc); - } else { // modules sub tree - n = handleModulesSubTree(name, loc); - } - } else { // Asking for a resource? /modules/java.base/java/lang/Object.class - if (isModules) { - n = handleResource(name); - } else { - // Possibly ask for /packages/java.lang/java.base - // although /packages/java.base not created - n = handleModuleLink(name); - } - } - return n; - } - - private void visitLocation(ImageLocation loc, LocationVisitor visitor) { - byte[] offsets = getResource(loc); - ByteBuffer buffer = ByteBuffer.wrap(offsets); - buffer.order(getByteOrder()); - IntBuffer intBuffer = buffer.asIntBuffer(); - for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) { - int offset = intBuffer.get(i); - ImageLocation pkgLoc = getLocation(offset); - visitor.visit(pkgLoc); - } - } - - private void visitPackageLocation(ImageLocation loc) { - // Retrieve package name - String pkgName = getBaseExt(loc); - // Content is array of offsets in Strings table - byte[] stringsOffsets = getResource(loc); - ByteBuffer buffer = ByteBuffer.wrap(stringsOffsets); - buffer.order(getByteOrder()); - IntBuffer intBuffer = buffer.asIntBuffer(); - // For each module, create a link node. - for (int i = 0; i < stringsOffsets.length / SIZE_OF_OFFSET; i++) { - // skip empty state, useless. - intBuffer.get(i); - i++; - int offset = intBuffer.get(i); - String moduleName = getString(offset); - Node targetNode = findNode("/modules/" + moduleName); - if (targetNode != null) { - String pkgDirName = packagesDir.getName() + "/" + pkgName; - Directory pkgDir = (Directory) nodes.get(pkgDirName); - newLinkNode(pkgDir, pkgDir.getName() + "/" + moduleName, targetNode); - } - } - } - - private Node handlePackages(String name, ImageLocation loc) { - long size = loc.getUncompressedSize(); - Node n = null; - // Only possiblities are /packages, /packages/package/module - if (name.equals("/packages")) { - visitLocation(loc, (childloc) -> { - findNode(childloc.getFullName()); - }); - packagesDir.setCompleted(true); - n = packagesDir; - } else { - if (size != 0) { // children are offsets to module in StringsTable - String pkgName = getBaseExt(loc); - Directory pkgDir = newDirectory(packagesDir, packagesDir.getName() + "/" + pkgName); - visitPackageLocation(loc); - pkgDir.setCompleted(true); - n = pkgDir; - } else { // Link to module - String pkgName = loc.getParent(); - String modName = getBaseExt(loc); - Node targetNode = findNode("/modules/" + modName); - if (targetNode != null) { - String pkgDirName = packagesDir.getName() + "/" + pkgName; - Directory pkgDir = (Directory) nodes.get(pkgDirName); - Node linkNode = newLinkNode(pkgDir, pkgDir.getName() + "/" + modName, targetNode); - n = linkNode; - } - } - } - return n; - } - - // Asking for /packages/package/module although - // /packages// not yet created, need to create it - // prior to return the link to module node. - private Node handleModuleLink(String name) { - // eg: unresolved /packages/package/module - // Build /packages/package node - Node ret = null; - String radical = "/packages/"; - String path = name; - if (path.startsWith(radical)) { - int start = radical.length(); - int pkgEnd = path.indexOf('/', start); - if (pkgEnd != -1) { - String pkg = path.substring(start, pkgEnd); - String pkgPath = radical + pkg; - Node n = findNode(pkgPath); - // If not found means that this is a symbolic link such as: - // /packages/java.util/java.base/java/util/Vector.class - // and will be done by a retry of the filesystem - for (Node child : n.getChildren()) { - if (child.name.equals(name)) { - ret = child; - break; - } - } - } - } - return ret; - } - - private Node handleModulesSubTree(String name, ImageLocation loc) { - Node n; - assert (name.equals(loc.getFullName())); - Directory dir = makeDirectories(name); - visitLocation(loc, (childloc) -> { - String path = childloc.getFullName(); - if (path.startsWith("/modules")) { // a package - makeDirectories(path); - } else { // a resource - makeDirectories(childloc.buildName(true, true, false)); - newResource(dir, childloc); - } - }); - dir.setCompleted(true); - n = dir; - return n; - } - - private Node handleResource(String name) { - Node n = null; - String locationPath = name.substring("/modules".length()); - ImageLocation resourceLoc = findLocation(locationPath); - if (resourceLoc != null) { - Directory dir = makeDirectories(resourceLoc.buildName(true, true, false)); - Resource res = newResource(dir, resourceLoc); - n = res; - } - return n; - } - - private String getBaseExt(ImageLocation loc) { - String base = loc.getBase(); - String ext = loc.getExtension(); - if (ext != null && !ext.isEmpty()) { - base = base + "." + ext; - } - return base; - } - - public synchronized Node findNode(String name) { - buildRootDirectory(); - Node n = nodes.get(name); - if (n == null || !n.isCompleted()) { - n = buildNode(name); - } - return n; - } - - private synchronized void clearNodes() { - nodes.clear(); - rootDir = null; - } - - /** - * Returns the file attributes of the image file. - */ - private BasicFileAttributes imageFileAttributes() { - BasicFileAttributes attrs = imageFileAttributes; - if (attrs == null) { - try { - Path file = getImagePath(); - attrs = Files.readAttributes(file, BasicFileAttributes.class); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - imageFileAttributes = attrs; - } - return attrs; - } - - private Directory buildRootDirectory() { - Directory root = rootDir; // volatile read - if (root != null) { - return root; - } - - synchronized (this) { - root = rootDir; - if (root != null) { - return root; - } - - // FIXME no time information per resource in jimage file (yet?) - // we use file attributes of jimage itself. - // root directory - root = newDirectory(null, "/"); - root.setIsRootDir(); - - // /packages dir - packagesDir = newDirectory(root, "/packages"); - packagesDir.setIsPackagesDir(); - - // /modules dir - modulesDir = newDirectory(root, "/modules"); - modulesDir.setIsModulesDir(); - - root.setCompleted(true); - return rootDir = root; - } - } - - private Directory newDirectory(Directory parent, String name) { - Directory dir = Directory.create(parent, name, imageFileAttributes()); - nodes.put(dir.getName(), dir); - return dir; - } - - private Resource newResource(Directory parent, ImageLocation loc) { - Resource res = Resource.create(parent, loc, imageFileAttributes()); - nodes.put(res.getName(), res); - return res; - } - - private LinkNode newLinkNode(Directory dir, String name, Node link) { - LinkNode linkNode = LinkNode.create(dir, name, link); - nodes.put(linkNode.getName(), linkNode); - return linkNode; - } - - private Directory makeDirectories(String parent) { - Directory last = rootDir; - for (int offset = parent.indexOf('/', 1); - offset != -1; - offset = parent.indexOf('/', offset + 1)) { - String dir = parent.substring(0, offset); - last = makeDirectory(dir, last); - } - return makeDirectory(parent, last); - - } - - private Directory makeDirectory(String dir, Directory last) { - Directory nextDir = (Directory) nodes.get(dir); - if (nextDir == null) { - nextDir = newDirectory(last, dir); - } - return nextDir; - } - - public byte[] getResource(Node node) throws IOException { - if (node.isResource()) { - return super.getResource(node.getLocation()); - } - throw new IOException("Not a resource: " + node); - } - - public byte[] getResource(Resource rs) throws IOException { - return super.getResource(rs.getLocation()); - } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java index d5984095e99..5f0433b9d3b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java @@ -299,13 +299,9 @@ class JrtFileSystem extends FileSystem { } // clean up this file system - called from finalize and close - void cleanup() throws IOException { - if (!isOpen) { - return; - } - synchronized (this) { + synchronized void cleanup() throws IOException { + if (isOpen) { isOpen = false; - // close image reader and null out image.close(); image = null; } @@ -461,8 +457,8 @@ class JrtFileSystem extends FileSystem { private Node lookup(String path) { try { return image.findNode(path); - } catch (RuntimeException re) { - throw new InvalidPathException(path, re.toString()); + } catch (RuntimeException | IOException ex) { + throw new InvalidPathException(path, ex.toString()); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java index 7b155feba88..2da0d6ed452 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java @@ -49,7 +49,7 @@ import jdk.internal.jimage.ImageReader.Node; */ abstract class SystemImage { - abstract Node findNode(String path); + abstract Node findNode(String path) throws IOException; abstract byte[] getResource(Node node) throws IOException; abstract void close() throws IOException; @@ -60,7 +60,7 @@ abstract class SystemImage { image.getRootDirectory(); return new SystemImage() { @Override - Node findNode(String path) { + Node findNode(String path) throws IOException { return image.findNode(path); } @Override From c20a95b52d5e32ad7fb9cde3e755f271f76cef9c Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 25 Apr 2016 09:57:55 -0300 Subject: [PATCH 138/222] 8154090: Remove support for jimage recreate Reviewed-by: alanb --- .../jdk/tools/jimage/ExtractedImage.java | 78 ------------------- .../classes/jdk/tools/jimage/JImageTask.java | 43 ++-------- .../tools/jimage/resources/jimage.properties | 23 ++---- jdk/test/tools/jimage/JImageTest.java | 49 ------------ jdk/test/tools/jimage/JImageToolTest.java | 4 - jdk/test/tools/lib/tests/JImageGenerator.java | 4 - 6 files changed, 12 insertions(+), 189 deletions(-) delete mode 100644 jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/ExtractedImage.java diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/ExtractedImage.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/ExtractedImage.java deleted file mode 100644 index 7090f768eb0..00000000000 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/ExtractedImage.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 jdk.tools.jimage; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.function.Consumer; -import jdk.tools.jlink.internal.ImageFileCreator; -import jdk.tools.jlink.internal.Archive; -import jdk.tools.jlink.internal.ImagePluginStack; -import jdk.tools.jlink.internal.DirArchive; -/** - * - * Support for extracted image. - */ -public final class ExtractedImage { - - private Set archives = new HashSet<>(); - private final ImagePluginStack plugins; - - ExtractedImage(Path dirPath, ImagePluginStack plugins, PrintWriter log, - boolean verbose) throws IOException { - if (!Files.isDirectory(dirPath)) { - throw new IOException("Not a directory"); - } - Consumer cons = (String t) -> { - if (verbose) { - log.println(t); - } - }; - this.plugins = plugins; - Files.walk(dirPath, 1).forEach((p) -> { - if (!dirPath.equals(p)) { - if (Files.isDirectory(p)) { - Archive a = new DirArchive(p, cons); - archives.add(a); - } - } - }); - archives = Collections.unmodifiableSet(archives); - } - - void recreateJImage(Path path) throws IOException { - ImageFileCreator.recreateJimage(path, archives, plugins); - } - - private static String getPathName(Path path) { - return path.toString().replace(File.separatorChar, '/'); - } -} diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java index 105e8f61b44..26acec228bb 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java @@ -32,7 +32,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.FileChannel; import java.nio.file.Files; -import java.nio.file.Path; import static java.nio.file.StandardOpenOption.READ; import static java.nio.file.StandardOpenOption.WRITE; import java.util.LinkedList; @@ -44,8 +43,6 @@ import static jdk.internal.jimage.ImageHeader.MAJOR_VERSION; import static jdk.internal.jimage.ImageHeader.MINOR_VERSION; import jdk.internal.jimage.ImageLocation; import jdk.tools.jlink.internal.ImageResourcesTree; -import jdk.tools.jlink.internal.ImagePluginConfiguration; -import jdk.tools.jlink.internal.ImagePluginStack; import jdk.tools.jlink.internal.TaskHelper; import jdk.tools.jlink.internal.TaskHelper.BadArgs; import static jdk.tools.jlink.internal.TaskHelper.JIMAGE_BUNDLE; @@ -97,7 +94,6 @@ class JImageTask { EXTRACT, INFO, LIST, - RECREATE, SET, VERIFY }; @@ -160,18 +156,20 @@ class JImageTask { try { List unhandled = optionsHelper.handleOptions(this, args); if(!unhandled.isEmpty()) { - options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase()); + try { + options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase()); + } catch (IllegalArgumentException ex) { + throw taskHelper.newBadArgs("err.not.a.task", unhandled.get(0)); + } for(int i = 1; i < unhandled.size(); i++) { options.jimages.add(new File(unhandled.get(i))); } + } else { + throw taskHelper.newBadArgs("err.not.a.task", ""); } if (options.help) { optionsHelper.showHelp(PROGNAME); } - if(optionsHelper.listPlugins()) { - optionsHelper.listPlugins(true); - return EXIT_OK; - } if (options.version || options.fullVersion) { taskHelper.showVersion(options.fullVersion); } @@ -191,30 +189,6 @@ class JImageTask { } } - private void recreate() throws Exception, BadArgs { - File directory = new File(options.directory); - if (!directory.isDirectory()) { - throw taskHelper.newBadArgs("err.not.a.dir", directory.getAbsolutePath()); - } - Path dirPath = directory.toPath(); - if (options.jimages.isEmpty()) { - throw taskHelper.newBadArgs("err.jimage.not.specified"); - } else if (options.jimages.size() != 1) { - throw taskHelper.newBadArgs("err.only.one.jimage"); - } - - Path jimage = options.jimages.get(0).toPath(); - - if (jimage.toFile().createNewFile()) { - ImagePluginStack pc = ImagePluginConfiguration.parseConfiguration(taskHelper. - getPluginsConfig(null, false)); - ExtractedImage img = new ExtractedImage(dirPath, pc, log, options.verbose); - img.recreateJImage(jimage); - } else { - throw taskHelper.newBadArgs("err.jimage.already.exists", jimage.getFileName()); - } - } - private void title(File file, BasicImageReader reader) { log.println("jimage: " + file.getName()); } @@ -379,9 +353,6 @@ class JImageTask { case LIST: iterate(this::listTitle, this::list); break; - case RECREATE: - recreate(); - break; case SET: iterate(this::set, null); break; diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties index 857d52b005a..99d2d4706d5 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties @@ -1,30 +1,25 @@ main.usage.summary=\ -Usage: {0} jimage...\n\ +Usage: {0} jimage...\n\ use --help for a list of possible options main.usage=\ -Usage: {0} jimage...\n\ +Usage: {0} jimage...\n\ \n\ \ extract - Extract all jimage entries into separate files into the directory\n\ \ specified by --dir= (default='.')\n\ \ info - Prints information specified in the jimage header.\n\ \ list - Prints the names of all the entries in the jimage. When used with\n\ \ --verbose will also print entry attributes ex. size and offset.\n\ -\ recreate - Reconstructs a jimage from an extracted directory (--dir)\n\ \ set - sets the value of specific jimage header entries\n\ \ verify - Reports errors on any .class entries that don't verify as classes.\n\ \n\ Possible options include: -main.extended.help=\ -jimage recreate is extensible by the main of plugins. Following plugins have been discovered \ -thanks to ServiceLoader and can be used when re-creating a jimage. - error.prefix=Error: warn.prefix=Warning: main.opt.dir=\ -\ --dir Target directory for extract/recreate +\ --dir Target directory for extract main.opt.flags=\ \ --flags=value Set the jimage flags to value @@ -38,14 +33,8 @@ main.opt.verbose=\ main.opt.version=\ \ --version Version information -main.opt.configuration=\ -\ --configuration Path to properties file containing defaults\ -\ options for recreate - main.command.files=\ \ @ Read options from file - -err.cannot.create.dir=cannot create directory: {0} err.cannot.read.file=cannot read file: {0} err.cannot.update.file=cannot update file: {0} err.file.not.found=cannot find file: {0} @@ -53,12 +42,10 @@ err.file.error=cannot access file: {0} err.flags.not.int=--flags value not integer: {0} err.internal.error=internal error: {0} {1} {2} err.invalid.arg.for.option=invalid argument for option: {0} -err.invalid.task=task must be extract|recreate|info|list|verify: {0} -err.jimage.already.exists=jimage already exists: {0} -err.jimage.not.specified=no jimage specified +err.invalid.task=task must be extract|info|list|verify: {0} err.missing.arg=no value given for {0} err.not.a.dir=not a directory: {0} err.not.a.jimage=not a jimage file: {0} -err.only.one.jimage=only one jimage should be specified +err.not.a.task=not a valid task: {0} err.option.unsupported={0} not supported: {1} err.unknown.option=unknown option: {0} diff --git a/jdk/test/tools/jimage/JImageTest.java b/jdk/test/tools/jimage/JImageTest.java index be1e784c070..fa2c08b08dd 100644 --- a/jdk/test/tools/jimage/JImageTest.java +++ b/jdk/test/tools/jimage/JImageTest.java @@ -110,54 +110,5 @@ public class JImageTest { .dir(helper.createNewExtractedDir("modules")) .image(image.resolve("lib").resolve("modules")) .extract().assertSuccess(); - - Path recreatedImage = JImageGenerator.getJImageTask() - .dir(extractedDir) - .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) - .recreate().assertSuccess(); - JImageValidator.validate(recreatedImage, bootClasses, Collections.emptyList()); - - // Check replacing the boot image by recreated one - Path destFile = image.resolve("lib").resolve("modules"); - Files.copy(recreatedImage, destFile, REPLACE_EXISTING); - JImageValidator validator = new JImageValidator(module, Collections.emptyList(), - image.toFile(), Collections.emptyList(), Collections.emptyList()); - validator.validate(); - - Path recreatedImage2 = JImageGenerator.getJImageTask() - .dir(extractedDir) - .option("--compress").option("2") - .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) - .recreate().assertSuccess(); - JImageValidator.validate(recreatedImage2, bootClasses, Collections.emptyList()); - - Path recreatedImage3 = JImageGenerator.getJImageTask() - .dir(extractedDir) - .option("--strip-debug") - .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) - .recreate().assertSuccess(); - JImageValidator.validate(recreatedImage3, bootClasses, Collections.emptyList()); - - Path recreatedImage4 = JImageGenerator.getJImageTask() - .dir(extractedDir) - .option("--exclude-resources") - .option("*.jcov, */META-INF/*") - .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) - .recreate().assertSuccess(); - List unexpectedPaths = new ArrayList<>(); - unexpectedPaths.add(".jcov"); - unexpectedPaths.add("/META-INF/"); - JImageValidator.validate(recreatedImage4, bootClasses, unexpectedPaths); - - Path recreatedImage5 = JImageGenerator.getJImageTask() - .dir(extractedDir) - .option("--compress") - .option("2") - .option("--strip-debug") - .option("--exclude-resources") - .option("*.jcov, */META-INF/*") - .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) - .recreate().assertSuccess(); - JImageValidator.validate(recreatedImage5, bootClasses, unexpectedPaths); } } diff --git a/jdk/test/tools/jimage/JImageToolTest.java b/jdk/test/tools/jimage/JImageToolTest.java index 18f22f12fb1..48195c4c1da 100644 --- a/jdk/test/tools/jimage/JImageToolTest.java +++ b/jdk/test/tools/jimage/JImageToolTest.java @@ -63,11 +63,7 @@ public class JImageToolTest { String jimage = jimagePath.toAbsolutePath().toString(); String bootimage = modulesimagePath.toAbsolutePath().toString(); String extractDir = Paths.get(".", "extract").toAbsolutePath().toString(); - String recreateImage = Paths.get(".", "recreate").toAbsolutePath().toString(); - String relativeRecreateImage = Paths.get(".", "recreate2").toString(); jimage("extract", "--dir", extractDir, bootimage); - jimage("recreate", "--dir", extractDir, recreateImage); - jimage("recreate", "--dir", extractDir, relativeRecreateImage); System.out.println("Test successful"); } else { System.out.println("Test skipped, not an images build"); diff --git a/jdk/test/tools/lib/tests/JImageGenerator.java b/jdk/test/tools/lib/tests/JImageGenerator.java index 77366aafb13..c75164b69cc 100644 --- a/jdk/test/tools/lib/tests/JImageGenerator.java +++ b/jdk/test/tools/lib/tests/JImageGenerator.java @@ -553,10 +553,6 @@ public class JImageGenerator { public Result extract() { return cmd("extract", dir); } - - public Result recreate() { - return cmd("recreate", image); - } } public static class JLinkTask { From d83717b035492c9ec6ca3a1092ba721a4c492e25 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 25 Apr 2016 09:57:55 -0300 Subject: [PATCH 139/222] 8069079: jimage extract / list to organize classes by modules Reviewed-by: alanb, mchung --- .../classes/jdk/tools/jimage/JImageTask.java | 86 +++++++++++++------ .../tools/jimage/resources/jimage.properties | 1 + 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java index 26acec228bb..b8a2d58c7fc 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java @@ -189,25 +189,19 @@ class JImageTask { } } - private void title(File file, BasicImageReader reader) { - log.println("jimage: " + file.getName()); - } - private void listTitle(File file, BasicImageReader reader) { - title(file, reader); - - if (options.verbose) { - log.print(pad("Offset", OFFSET_WIDTH + 1)); - log.print(pad("Size", SIZE_WIDTH + 1)); - log.print(pad("Compressed", COMPRESSEDSIZE_WIDTH + 1)); - log.println(" Entry"); - } + log.println("jimage: " + file); } private interface JImageAction { public void apply(File file, BasicImageReader reader) throws IOException, BadArgs; } + private interface ModuleAction { + public void apply(BasicImageReader reader, + String oldModule, String newModule) throws IOException, BadArgs; + } + private interface ResourceAction { public void apply(BasicImageReader reader, String name, ImageLocation location) throws IOException, BadArgs; @@ -233,23 +227,32 @@ class JImageTask { } } - private static final int NUMBER_WIDTH = 12; - private static final int OFFSET_WIDTH = NUMBER_WIDTH; - private static final int SIZE_WIDTH = NUMBER_WIDTH; - private static final int COMPRESSEDSIZE_WIDTH = NUMBER_WIDTH; + private static final int OFFSET_WIDTH = 12; + private static final int SIZE_WIDTH = 10; + private static final int COMPRESSEDSIZE_WIDTH = 10; - private void print(String entry, ImageLocation location) { + private String trimModule(String name) { + int offset = name.indexOf('/', 1); + + if (offset != -1 && offset + 1 < name.length()) { + return name.substring(offset + 1); + } + + return name; + } + + private void print(String name, ImageLocation location) { log.print(pad(location.getContentOffset(), OFFSET_WIDTH) + " "); log.print(pad(location.getUncompressedSize(), SIZE_WIDTH) + " "); log.print(pad(location.getCompressedSize(), COMPRESSEDSIZE_WIDTH) + " "); - log.println(entry); + log.println(trimModule(name)); } - private void print(BasicImageReader reader, String entry) { + private void print(BasicImageReader reader, String name) { if (options.verbose) { - print(entry, reader.findLocation(entry)); + print(name, reader.findLocation(name)); } else { - log.println(entry); + log.println(" " + trimModule(name)); } } @@ -268,6 +271,18 @@ class JImageTask { log.println(" Index Size: " + header.getIndexSize()); } + private void listModule(BasicImageReader reader, String oldModule, String newModule) { + log.println(); + log.println("Module: " + newModule); + + if (options.verbose) { + log.print(pad("Offset", OFFSET_WIDTH) + " "); + log.print(pad("Size", SIZE_WIDTH) + " "); + log.print(pad("Compressed", COMPRESSEDSIZE_WIDTH) + " "); + log.println("Entry"); + } + } + private void list(BasicImageReader reader, String name, ImageLocation location) { print(reader, name); } @@ -317,7 +332,12 @@ class JImageTask { } private void iterate(JImageAction jimageAction, + ModuleAction moduleAction, ResourceAction resourceAction) throws IOException, BadArgs { + if (options.jimages.isEmpty()) { + throw taskHelper.newBadArgs("err.no.jimage"); + } + for (File file : options.jimages) { if (!file.exists() || !file.isFile()) { throw taskHelper.newBadArgs("err.not.a.jimage", file.getName()); @@ -330,9 +350,23 @@ class JImageTask { if (resourceAction != null) { String[] entryNames = reader.getEntryNames(); + String oldModule = ""; for (String name : entryNames) { if (!ImageResourcesTree.isTreeInfoResource(name)) { + if (moduleAction != null) { + int offset = name.indexOf('/', 1); + + String newModule = offset != -1 ? + name.substring(1, offset) : + ""; + + if (!oldModule.equals(newModule)) { + moduleAction.apply(reader, oldModule, newModule); + oldModule = newModule; + } + } + ImageLocation location = reader.findLocation(name); resourceAction.apply(reader, name, location); } @@ -345,19 +379,19 @@ class JImageTask { private boolean run() throws Exception, BadArgs { switch (options.task) { case EXTRACT: - iterate(null, this::extract); + iterate(null, null, this::extract); break; case INFO: - iterate(this::info, null); + iterate(this::info, null, null); break; case LIST: - iterate(this::listTitle, this::list); + iterate(this::listTitle, this::listModule, this::list); break; case SET: - iterate(this::set, null); + iterate(this::set, null, null); break; case VERIFY: - iterate(this::title, this::verify); + iterate(this::listTitle, null, this::verify); break; default: throw taskHelper.newBadArgs("err.invalid.task", options.task.name()).showUsage(true); diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties index 99d2d4706d5..ef94fd376c6 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties @@ -46,6 +46,7 @@ err.invalid.task=task must be extract|info|list|verify: {0} err.missing.arg=no value given for {0} err.not.a.dir=not a directory: {0} err.not.a.jimage=not a jimage file: {0} +err.no.jimage=no jimage provided err.not.a.task=not a valid task: {0} err.option.unsupported={0} not supported: {1} err.unknown.option=unknown option: {0} From 7057b40f4859efe2af4fcb48b9c9636ce8d6682e Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 25 Apr 2016 09:57:56 -0300 Subject: [PATCH 140/222] 8154179: BasicImageReader activating ImageBufferCache when not used Reviewed-by: redestad --- .../share/classes/jdk/internal/jimage/BasicImageReader.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java index 4c70a9b1547..9b21fb6c1be 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java @@ -183,7 +183,9 @@ public class BasicImageReader implements AutoCloseable { } public static void releaseByteBuffer(ByteBuffer buffer) { - ImageBufferCache.releaseBuffer(buffer); + if (!MAP_ALL) { + ImageBufferCache.releaseBuffer(buffer); + } } public String getName() { From c95df8b9fe59a9af82f316853dc9fee0dd9deab7 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 25 Apr 2016 09:59:07 -0300 Subject: [PATCH 141/222] 8147426: Missing definition for JIMAGE_NOT_FOUND Reviewed-by: hseigel, alanb --- hotspot/src/share/vm/classfile/jimage.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/classfile/jimage.hpp b/hotspot/src/share/vm/classfile/jimage.hpp index e538ac805f8..480d01bc149 100644 --- a/hotspot/src/share/vm/classfile/jimage.hpp +++ b/hotspot/src/share/vm/classfile/jimage.hpp @@ -30,7 +30,7 @@ class JImageFile; typedef jlong JImageLocationRef; // Max path length limit independent of platform. Windows max path is 1024, -// other platforms use 4096. The JCK fails several tests when 1024 is used. +// other platforms use 4096. #define JIMAGE_MAX_PATH 4096 // JImage Error Codes @@ -113,7 +113,8 @@ typedef const char* (*JImagePackageToModule_t)(JImageFile* jimage, const char* p * * Ex. * jlong size; - * JImageLocationRef location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size); + * JImageLocationRef location = (*JImageFindResource)(image, + * "java.base", "9.0", "java/lang/String.class", &size); */ extern "C" JImageLocationRef JIMAGE_FindResource(JImageFile* jimage, const char* module_name, const char* version, const char* name, @@ -134,7 +135,8 @@ typedef JImageLocationRef(*JImageFindResource_t)(JImageFile* jimage, * * Ex. * jlong size; - * JImageLocationRef location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size); + * JImageLocationRef location = (*JImageFindResource)(image, + * "java.base", "9.0", "java/lang/String.class", &size); * char* buffer = new char[size]; * (*JImageGetResource)(image, location, buffer, size); */ @@ -154,7 +156,8 @@ typedef jlong(*JImageGetResource_t)(JImageFile* jimage, JImageLocationRef locati * required. All strings are utf-8, zero byte terminated.file. * * Ex. - * bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version, const char* package, const char* name, const char* extension, void* arg) { + * bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version, + * const char* package, const char* name, const char* extension, void* arg) { * if (strcmp(extension, “class”) == 0) { * char path[JIMAGE_MAX_PATH]; * Thread* THREAD = Thread::current(); From ce076f3ab97f97e0a6e2027deb666a4b9409e1c6 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 25 Apr 2016 09:59:43 -0300 Subject: [PATCH 142/222] 8147634: Need a JImage API that given a JImageLocationRef returns class name Reviewed-by: hseigel --- hotspot/src/share/vm/classfile/classLoader.cpp | 15 +++++++++------ hotspot/src/share/vm/classfile/jimage.hpp | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index a8a86765970..19b0f460a9d 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -98,12 +98,13 @@ static Crc32_t Crc32 = NULL; // Entry points for jimage.dll for loading jimage file entries -static JImageOpen_t JImageOpen = NULL; -static JImageClose_t JImageClose = NULL; -static JImagePackageToModule_t JImagePackageToModule = NULL; -static JImageFindResource_t JImageFindResource = NULL; -static JImageGetResource_t JImageGetResource = NULL; -static JImageResourceIterator_t JImageResourceIterator = NULL; +static JImageOpen_t JImageOpen = NULL; +static JImageClose_t JImageClose = NULL; +static JImagePackageToModule_t JImagePackageToModule = NULL; +static JImageFindResource_t JImageFindResource = NULL; +static JImageGetResource_t JImageGetResource = NULL; +static JImageResourceIterator_t JImageResourceIterator = NULL; +static JImage_ResourcePath_t JImageResourcePath = NULL; // Globals @@ -925,6 +926,8 @@ void ClassLoader::load_jimage_library() { guarantee(JImageGetResource != NULL, "function JIMAGE_GetResource not found"); JImageResourceIterator = CAST_TO_FN_PTR(JImageResourceIterator_t, os::dll_lookup(handle, "JIMAGE_ResourceIterator")); guarantee(JImageResourceIterator != NULL, "function JIMAGE_ResourceIterator not found"); + JImageResourcePath = CAST_TO_FN_PTR(JImage_ResourcePath_t, os::dll_lookup(handle, "JIMAGE_ResourcePath")); + guarantee(JImageResourcePath != NULL, "function JIMAGE_ResourcePath not found"); } jboolean ClassLoader::decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg) { diff --git a/hotspot/src/share/vm/classfile/jimage.hpp b/hotspot/src/share/vm/classfile/jimage.hpp index 480d01bc149..f34ba6efde9 100644 --- a/hotspot/src/share/vm/classfile/jimage.hpp +++ b/hotspot/src/share/vm/classfile/jimage.hpp @@ -179,3 +179,20 @@ extern "C" void JIMAGE_ResourceIterator(JImageFile* jimage, typedef void (*JImageResourceIterator_t)(JImageFile* jimage, JImageResourceVisitor_t visitor, void* arg); + +/* + * JIMAGE_ResourcePath- Given an open image file, a location reference, a buffer + * and a maximum buffer size, copy the path of the resource into the buffer. + * Returns false if not a valid location reference. + * + * Ex. + * JImageLocationRef location = ... + * char path[JIMAGE_MAX_PATH]; + * (*JImageResourcePath)(image, location, path, JIMAGE_MAX_PATH); + */ +extern "C" bool JIMAGE_ResourcePath(JImageFile* image, JImageLocationRef locationRef, + char* path, size_t max); + +typedef bool (*JImage_ResourcePath_t)(JImageFile* jimage, JImageLocationRef location, + char* buffer, jlong size); + From 1c8cb8707ce006fafcec9fc6f11820f8817e710e Mon Sep 17 00:00:00 2001 From: Alexander Stepanov Date: Mon, 25 Apr 2016 18:07:45 +0300 Subject: [PATCH 143/222] 8154962: [TEST] @BeanProperty: add some tests for anonimous classes Reviewed-by: serb --- .../AnonymousClassBeanPropertyTest.java | 867 ++++++++++++++++++ .../beans/Introspector/BeanPropertyTest.java | 107 ++- 2 files changed, 931 insertions(+), 43 deletions(-) create mode 100644 jdk/test/java/beans/Introspector/AnonymousClassBeanPropertyTest.java diff --git a/jdk/test/java/beans/Introspector/AnonymousClassBeanPropertyTest.java b/jdk/test/java/beans/Introspector/AnonymousClassBeanPropertyTest.java new file mode 100644 index 00000000000..a8ec7d49188 --- /dev/null +++ b/jdk/test/java/beans/Introspector/AnonymousClassBeanPropertyTest.java @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.beans.BeanInfo; +import java.beans.BeanProperty; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; + +import java.util.Arrays; + + +/** + * @test + * @bug 8132973 8132732 8155013 + * @summary Some check for BeanProperty annotation + * @author a.stepanov + * @run main AnonymousClassBeanPropertyTest + */ + + +public class AnonymousClassBeanPropertyTest { + + private final static String DESCRIPTION = "TEST"; + private final static boolean BOUND = true; + private final static boolean EXPERT = false; + private final static boolean HIDDEN = true; + private final static boolean PREFERRED = false; + private final static boolean REQUIRED = true; + private final static boolean UPDATE = false; + + private final static double X = java.lang.Math.PI; + + private final static String + V_NAME = "java.lang.Math.PI", + V_SHORT = "PI", + V = Double.toString(X); + + private final static String DESCRIPTION_2 = "XYZ"; + + + // ---------- test cases (interfaces) ---------- + + private interface IGet { + double getX(); + } + + private interface ISet { + void setX(double v); + } + + private interface IGetByIndex { + double getX(int i); + } + + private interface ISetByIndex { + void setX(int i, double v); + } + + private interface IGetArray { + double[] getX(); + } + + private interface ISetArray { + void setX(double a[]); + } + + private interface IGetBoth { + double getX(int i); + double[] getX(); + } + + private interface ISetBoth { + void setX(int i, double v); + void setX(double a[]); + } + + private interface IGetSet { + double getX(); + void setX(double v); + } + + private interface IGetSetByIndex { + double getX(int i); + void setX(int i, double v); + } + + private interface IGetSetBoth { + double getX(int i); + double[] getX(); + void setX(int i, double v); + void setX(double a[]); + } + + + // ---------- checks ---------- + + private static boolean check(String what, boolean v, boolean ref) { + + boolean ok = (v == ref); + if (!ok) { System.out.println( + "invalid " + what + ": " + v + ", expected: " + ref); } + return ok; + } + + private static boolean checkInfo(Class c, String what) { + + BeanInfo i; + try { i = Introspector.getBeanInfo(c, Object.class); } + catch (IntrospectionException e) { throw new RuntimeException(e); } + + System.out.println("\nchecking info for " + what); + + PropertyDescriptor descriptors[] = i.getPropertyDescriptors(); + int nd = descriptors.length; + if (nd != 1) { + System.out.println("invalid number of descriptors: " + nd); + return false; + } + + PropertyDescriptor d = descriptors[0]; + + String descr = d.getShortDescription(); + boolean ok = descr.equals(DESCRIPTION); + if (!ok) { System.out.println("invalid description: " + descr + + ", expected: " + DESCRIPTION); } + + ok &= check("isBound", d.isBound(), BOUND); + ok &= check("isExpert", d.isExpert(), EXPERT); + ok &= check("isHidden", d.isHidden(), HIDDEN); + ok &= check("isPreferred", d.isPreferred(), PREFERRED); + ok &= check("required", (boolean) d.getValue("required"), REQUIRED); + ok &= check("visualUpdate", + (boolean) d.getValue("visualUpdate"), UPDATE); + + Object vals[] = (Object[]) d.getValue("enumerationValues"); + if (vals == null) { + System.out.println("null enumerationValues"); + return false; + } + + if (vals.length == 0) { + System.out.println("empty enumerationValues"); + return false; + } + + boolean okVals = ( + (vals.length == 3) && + vals[0].toString().equals(V_SHORT) && + vals[1].toString().equals(V) && + vals[2].toString().equals(V_NAME)); + + if (!okVals) { + System.out.println("invalid enumerationValues:"); + for (Object v: vals) { System.out.println(v.toString()); } + } + + return (ok && okVals); + } + + private static boolean checkAlternativeInfo(Class c, String what) { + + BeanInfo i; + try { i = Introspector.getBeanInfo(c, Object.class); } + catch (IntrospectionException e) { throw new RuntimeException(e); } + + System.out.println("checking alternative info for " + what); + + PropertyDescriptor descriptors[] = i.getPropertyDescriptors(); + int nd = descriptors.length; + if (nd != 1) { + System.out.println("invalid number of descriptors: " + nd); + return false; + } + + PropertyDescriptor d = descriptors[0]; + + String descr = d.getShortDescription(); + boolean ok = descr.equals(DESCRIPTION_2); + if (!ok) { System.out.println("invalid alternative description: " + + descr + ", expected: " + DESCRIPTION_2); } + + ok &= check("isBound", d.isBound(), !BOUND); + ok &= check("isExpert", d.isExpert(), !EXPERT); + ok &= check("isHidden", d.isHidden(), !HIDDEN); + ok &= check("isPreferred", d.isPreferred(), !PREFERRED); + ok &= check("required", (boolean) d.getValue("required"), !REQUIRED); + ok &= check("visualUpdate", + (boolean) d.getValue("visualUpdate"), !UPDATE); + + Object vals[] = (Object[]) d.getValue("enumerationValues"); + if (vals != null || vals.length > 0) { + System.out.println("non-empty enumerationValues"); + return false; + } + + return ok; + } + + + + // ---------- run tests ---------- + + public static void main(String[] args) { + + boolean passed = true, ok, ok2; + + //---------------------------------------------------------------------- + + IGet testGet = new IGet() { + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double getX() { return X; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGet.getClass(), "IGet"); + System.out.println("OK = " + ok); + passed = passed && ok; + + //---------------------------------------------------------------------- + + ISet testSet = new ISet() { + + private double x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public void setX(double v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testSet.getClass(), "ISet"); + System.out.println("OK = " + ok); + passed = passed && ok; + + //---------------------------------------------------------------------- + + IGetByIndex testGetByIndex = new IGetByIndex() { + + private final double x[] = {X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double getX(int i) { return x[i]; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetByIndex.getClass(), "IGetByIndex"); + System.out.println("OK = " + ok); + passed = passed && ok; + + //---------------------------------------------------------------------- + + ISetByIndex testSetByIndex = new ISetByIndex() { + + private final double x[] = {X, X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public void setX(int i, double v) { x[i] = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testSetByIndex.getClass(), "ISetByIndex"); + System.out.println("OK = " + ok); + passed = passed && ok; + + //---------------------------------------------------------------------- + + // TODO: please uncomment/update after 8155013 fix + /* + IGetArray testGetArray = new IGetArray() { + + private final double x[] = {X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double[] getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetArray.getClass(), "IGetArray"); + System.out.println("OK = " + ok); + passed = passed && ok; + */ + + //---------------------------------------------------------------------- + + // TODO: please uncomment/update after 8155013 fix + /* + ISetArray testSetArray = new ISetArray() { + + private double x[]; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public void setX(double a[]) { x = Arrays.copyOf(a, a.length); } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testSetArray.getClass(), "ISetArray"); + System.out.println("OK = " + ok); + passed = passed && ok; + */ + + //---------------------------------------------------------------------- + + IGetBoth testGetBoth_1 = new IGetBoth() { + + private final double x[] = {X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double getX(int i) { return x[i]; } + @Override + public double[] getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetBoth_1.getClass(), "IGetBoth-1"); + System.out.println("OK = " + ok); + passed = passed && ok; + + // TODO: please uncomment/update after 8155013 fix + /* + IGetBoth testGetBoth_2 = new IGetBoth() { + + private final double x[] = {X, X}; + + @Override + public double getX(int i) { return x[i]; } + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double[] getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetBoth_2.getClass(), "IGetBoth-2"); + System.out.println("OK = " + ok); + passed = passed && ok; + */ + + // TODO: please uncomment/update after 8132732 fix + /* + IGetBoth testGetBoth_3 = new IGetBoth() { + + private final double x[] = {X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double getX(int i) { return x[i]; } + @BeanProperty( + description = DESCRIPTION_2, + bound = !BOUND, + expert = !EXPERT, + hidden = !HIDDEN, + preferred = !PREFERRED, + required = !REQUIRED, + visualUpdate = !UPDATE) + @Override + public double[] getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetBoth_3.getClass(), "IGetBoth-3"); + System.out.println("OK = " + ok); + ok2 = checkAlternativeInfo(testGetBoth_3.getClass(), "IGetBoth-3"); + System.out.println("OK = " + ok2); + passed = passed && ok && ok2; + */ + + //---------------------------------------------------------------------- + + ISetBoth testSetBoth_1 = new ISetBoth() { + + private double x[] = new double[3]; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public void setX(int i, double v) { x[i] = v; } + @Override + public void setX(double[] a) { x = Arrays.copyOf(a, a.length); } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testSetBoth_1.getClass(), "ISetBoth-1"); + System.out.println("OK = " + ok); + passed = passed && ok; + + // TODO: please uncomment/update after 8155013 fix + /* + ISetBoth testSetBoth_2 = new ISetBoth() { + + private double x[] = new double[3]; + + @Override + public void setX(int i, double v) { x[i] = v; } + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public void setX(double[] a) { x = Arrays.copyOf(a, a.length); } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testSetBoth_2.getClass(), "ISetBoth-2"); + System.out.println("OK = " + ok); + passed = passed && ok; + */ + + // TODO: please uncomment/update after 8132732 fix + /* + ISetBoth testSetBoth_3 = new ISetBoth() { + + private double x[] = {X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public void setX(int i, double v) { x[i] = v; } + @BeanProperty( + description = DESCRIPTION_2, + bound = !BOUND, + expert = !EXPERT, + hidden = !HIDDEN, + preferred = !PREFERRED, + required = !REQUIRED, + visualUpdate = !UPDATE) + @Override + public void setX(double[] a) { x = Arrays.copyOf(a, a.length); } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testSetBoth_3.getClass(), "ISetBoth-3"); + System.out.println("OK = " + ok); + ok2 = checkAlternativeInfo(testSetBoth_3.getClass(), "ISetBoth-3"); + System.out.println("OK = " + ok2); + passed = passed && ok && ok2; + */ + + //---------------------------------------------------------------------- + + IGetSet testGetSet_1 = new IGetSet() { + + private double x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double getX() { return x; } + @Override + public void setX(double v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetSet_1.getClass(), "IGetSet-1"); + System.out.println("OK = " + ok); + passed = passed && ok; + + + IGetSet testGetSet_2 = new IGetSet() { + + private double x; + + @Override + public double getX() { return x; } + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public void setX(double v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetSet_2.getClass(), "IGetSet-2"); + System.out.println("OK = " + ok); + passed = passed && ok; + + // TODO: please uncomment/update after 8132973 fix + /* + IGetSet testGetSet_3 = new IGetSet() { + + private double x; + + @Override + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public double getX() { return x; } + @BeanProperty( + description = DESCRIPTION_2, + bound = !BOUND, + expert = !EXPERT, + hidden = !HIDDEN, + preferred = !PREFERRED, + required = !REQUIRED, + visualUpdate = !UPDATE) + @Override + public void setX(double v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetSet_3.getClass(), "IGetSet-3"); + System.out.println("OK = " + ok); + ok2 = checkAlternativeInfo(testGetSet_3.getClass(), "IGetSet-3"); + System.out.println("OK = " + ok2); + passed = passed && ok && ok2; + */ + + //---------------------------------------------------------------------- + + IGetSetByIndex testGetSetByIndex_1 = new IGetSetByIndex() { + + private final double x[] = {X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double getX(int i) { return x[i]; } + @Override + public void setX(int i, double v) { x[i] = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetSetByIndex_1.getClass(), "IGetSetByIndex-1"); + System.out.println("OK = " + ok); + passed = passed && ok; + + + IGetSetByIndex testGetSetByIndex_2 = new IGetSetByIndex() { + + private final double x[] = {X, X}; + + @Override + public double getX(int i) { return x[i]; } + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public void setX(int i, double v) { x[i] = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetSetByIndex_2.getClass(), "IGetSetByIndex-2"); + System.out.println("OK = " + ok); + passed = passed && ok; + + // TODO: please uncomment/update after 8132973 fix + /* + IGetSetByIndex testGetSetByIndex_3 = new IGetSetByIndex() { + + private double x[] = {X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double getX(int i) { + return x[i]; + } + @BeanProperty( + description = DESCRIPTION_2, + bound = !BOUND, + expert = !EXPERT, + hidden = !HIDDEN, + preferred = !PREFERRED, + required = !REQUIRED, + visualUpdate = !UPDATE) + @Override + public void setX(int i, double v) { + x[i] = v; + } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetSetByIndex_3.getClass(), "IGetSetByIndex-3"); + System.out.println("OK = " + ok); + ok2 = checkAlternativeInfo( + testGetSetByIndex_3.getClass(), "IGetSetByIndex-3"); + System.out.println("OK = " + ok2); + passed = passed && ok && ok2; + */ + + //---------------------------------------------------------------------- + + // TODO: please uncomment/update after 8155013 fix + /* + IGetSetBoth testGetSetBoth_1 = new IGetSetBoth() { + + private double x[] = {X, X}; + + @Override + public double getX(int i) { return x[i]; } + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double[] getX() { return x; } + @Override + public void setX(int i, double v) { x[i] = v; } + @Override + public void setX(double[] a) { x = Arrays.copyOf(a, a.length); } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetSetBoth_1.getClass(), "IGetSetBoth-1"); + System.out.println("OK = " + ok); + passed = passed && ok; + */ + + // TODO: please uncomment/update after 8155013 fix + /* + IGetSetBoth testGetSetBoth_2 = new IGetSetBoth() { + + private double x[] = {X, X}; + + @Override + public double getX(int i) { return x[i]; } + @Override + public double[] getX() { return x; } + @Override + public void setX(int i, double v) { x[i] = v; } + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public void setX(double[] a) { x = Arrays.copyOf(a, a.length); } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetSetBoth_2.getClass(), "IGetSetBoth-2"); + System.out.println("OK = " + ok); + passed = passed && ok; + */ + + // TODO: please uncomment/update after 8132973 fix + /* + IGetSetBoth testGetSetBoth_3 = new IGetSetBoth() { + + private double x[] = {X, X}; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + @Override + public double getX(int i) { return x[i]; } + @Override + public double[] getX() { return x; } + @Override + public void setX(int i, double v) { x[i] = v; } + @BeanProperty( + description = DESCRIPTION_2, + bound = !BOUND, + expert = !EXPERT, + hidden = !HIDDEN, + preferred = !PREFERRED, + required = !REQUIRED, + visualUpdate = !UPDATE) + @Override + public void setX(double[] a) { x = Arrays.copyOf(a, a.length); } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + }; + ok = checkInfo(testGetSetBoth_3.getClass(), "IGetSetBoth-3"); + System.out.println("OK = " + ok); + ok2 = checkAlternativeInfo( + testGetSetBoth_3.getClass(), "IGetSetBoth-3"); + System.out.println("OK = " + ok2); + passed = passed && ok && ok2; + */ + + if (!passed) { throw new RuntimeException("test failed"); } + System.out.println("\ntest passed"); + } +} diff --git a/jdk/test/java/beans/Introspector/BeanPropertyTest.java b/jdk/test/java/beans/Introspector/BeanPropertyTest.java index 0344f378cc6..6f957074c6e 100644 --- a/jdk/test/java/beans/Introspector/BeanPropertyTest.java +++ b/jdk/test/java/beans/Introspector/BeanPropertyTest.java @@ -297,11 +297,7 @@ public class BeanPropertyTest { required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) - public int getX(int i) throws IndexOutOfBoundsException { - if (i < 0 || i >= x.length) { - throw new IndexOutOfBoundsException(); } - return x[i]; - } + public int getX(int i) { return x[i]; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} @@ -322,11 +318,7 @@ public class BeanPropertyTest { required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) - public void setX(int i, int v) throws IndexOutOfBoundsException { - if (i < 0 || i >= x.length) { - throw new IndexOutOfBoundsException(); } - x[i] = v; - } + public void setX(int i, int v) { x[i] = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} @@ -348,11 +340,7 @@ public class BeanPropertyTest { required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) - public int getX(int i) throws IndexOutOfBoundsException { - if (i < 0 || i >= x.length) { - throw new IndexOutOfBoundsException(); } - return x[i]; - } + public int getX(int i) { return x[i]; } public int[] getX() { return x; } @@ -376,11 +364,7 @@ public class BeanPropertyTest { required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) - public void setX(int i, int v) throws IndexOutOfBoundsException { - if (i < 0 || i >= x.length) { - throw new IndexOutOfBoundsException(); } - x[i] = v; - } + public void setX(int i, int v) { x[i] = v; } public void setX(int a[]) { x = Arrays.copyOf(a, a.length); } @@ -407,11 +391,7 @@ public class BeanPropertyTest { enumerationValues = {V_NAME}) public int[] getX() { return x; } - public int getX(int i) throws IndexOutOfBoundsException { - if (i < 0 || i >= x.length) { - throw new IndexOutOfBoundsException(); } - return x[i]; - } + public int getX(int i) { return x[i]; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} @@ -436,11 +416,7 @@ public class BeanPropertyTest { enumerationValues = {V_NAME}) public void setX(int a[]) { x = Arrays.copyOf(a, a.length); } - public void setX(int i, int v) throws IndexOutOfBoundsException { - if (i < 0 || i >= x.length) { - throw new IndexOutOfBoundsException(); } - x[i] = v; - } + public void setX(int i, int v) { x[i] = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} @@ -472,11 +448,7 @@ public class BeanPropertyTest { preferred = !PREFERRED, required = !REQUIRED, visualUpdate = !UPDATE) - public int getX(int i) throws IndexOutOfBoundsException { - if (i < 0 || i >= x.length) { - throw new IndexOutOfBoundsException(); } - return x[i]; - } + public int getX(int i) { return x[i]; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} @@ -508,11 +480,7 @@ public class BeanPropertyTest { preferred = !PREFERRED, required = !REQUIRED, visualUpdate = !UPDATE) - public void setX(int i, int v) throws IndexOutOfBoundsException { - if (i < 0 || i >= x.length) { - throw new IndexOutOfBoundsException(); } - x[i] = v; - } + public void setX(int i, int v) { x[i] = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} @@ -837,7 +805,53 @@ public class BeanPropertyTest { public void removePropertyChangeListener(PropertyChangeListener l) {} } + public static class Self { + private final static String TESTCASE = "trivial singleton"; + + private static Self instance = null; + private Self() {} + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE) + public Self getSelf() { + if (instance == null) { instance = new Self(); } + return instance; + } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class SelfArr { + + private final static String TESTCASE = "trivial singleton + array"; + + private static SelfArr arr[] = null; + private SelfArr() {} + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE) + public SelfArr[] getSelfArr() { + if (arr == null) { arr = new SelfArr[]{new SelfArr(), new SelfArr()}; } + return arr; + } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } // ---------- checks ---------- @@ -850,7 +864,7 @@ public class BeanPropertyTest { return ok; } - private static boolean checkInfo(BeanInfo i) { + private static boolean checkInfo(BeanInfo i, boolean checkVals) { System.out.println("checking info..."); @@ -876,6 +890,8 @@ public class BeanPropertyTest { ok &= check("visualUpdate", (boolean) d.getValue("visualUpdate"), UPDATE); + if (!checkVals) { return ok; } + Object vals[] = (Object[]) d.getValue("enumerationValues"); if (vals == null) { System.out.println("null enumerationValues"); @@ -936,6 +952,10 @@ public class BeanPropertyTest { c.equals(GS.class)); } + private static boolean ignoreVals(Class c) { + return (c.equals(Self.class) || c.equals(SelfArr.class)); + } + // ---------- run test ---------- @@ -959,7 +979,8 @@ public class BeanPropertyTest { // G14.class, S14.class, // TODO: please update after 8132888 fix or // remove these cases if it is not an issue // GS.class, // TODO: please update after 8132973 fix - getX.class, setX.class + getX.class, setX.class, + Self.class, SelfArr.class }; boolean passed = true; @@ -974,7 +995,7 @@ public class BeanPropertyTest { BeanInfo i; try { i = Introspector.getBeanInfo(c, Object.class); } catch (IntrospectionException e) { throw new RuntimeException(e); } - boolean ok = checkInfo(i); + boolean ok = checkInfo(i, !ignoreVals(c)); if (checkAlternative(c)) { ok |= checkAlternativeInfo(i); } From f49817d6cd8f90f86c7dc4c7ab3f7f058a91ddd0 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Mon, 25 Apr 2016 08:50:16 -0700 Subject: [PATCH 144/222] 8154485: JShell: infrastructure for multi-Snippet class wrappers Reviewed-by: jlahoda --- .../internal/jshell/remote/RemoteAgent.java | 7 +- .../internal/jshell/remote/RemoteCodes.java | 10 +- .../jshell/tool/resources/l10n.properties | 2 +- .../classes/jdk/jshell/ClassTracker.java | 13 ++- .../jdk/jshell/DeclarationSnippet.java | 2 +- .../share/classes/jdk/jshell/Diag.java | 9 +- .../share/classes/jdk/jshell/DiagList.java | 5 +- .../share/classes/jdk/jshell/Eval.java | 78 +++++++-------- .../classes/jdk/jshell/ExecutionControl.java | 9 +- .../share/classes/jdk/jshell/JShell.java | 5 +- .../jdk/jshell/OuterImportSnippetWrap.java | 61 ++++++++++++ .../jdk/jshell/OuterSnippetsClassWrap.java | 95 ++++++++++++++++++ .../share/classes/jdk/jshell/OuterWrap.java | 77 +++++---------- .../classes/jdk/jshell/OuterWrapMap.java | 98 +++++++++++++++++++ .../share/classes/jdk/jshell/Snippet.java | 10 +- .../share/classes/jdk/jshell/SnippetMaps.java | 31 +++--- .../jdk/jshell/SourceCodeAnalysisImpl.java | 19 ++-- .../share/classes/jdk/jshell/TaskFactory.java | 59 +++-------- .../classes/jdk/jshell/TreeDissector.java | 34 ++++--- .../share/classes/jdk/jshell/Unit.java | 70 ++++++++----- .../share/classes/jdk/jshell/Util.java | 8 +- .../share/classes/jdk/jshell/Wrap.java | 51 +++++++++- langtools/test/jdk/jshell/ClassesTest.java | 9 +- langtools/test/jdk/jshell/DropTest.java | 13 ++- langtools/test/jdk/jshell/KullaTesting.java | 2 +- langtools/test/jdk/jshell/MethodsTest.java | 29 +++++- langtools/test/jdk/jshell/ReplaceTest.java | 24 ++--- .../jdk/jshell/SnippetStatusListenerTest.java | 2 +- langtools/test/jdk/jshell/SnippetTest.java | 3 +- langtools/test/jdk/jshell/VariablesTest.java | 4 +- 30 files changed, 573 insertions(+), 266 deletions(-) create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterImportSnippetWrap.java create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterSnippetsClassWrap.java create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java index f7d8e4a186d..83d6419f86a 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java @@ -262,9 +262,14 @@ class RemoteAgent { } } + /** + * Expunge internal info from string + * @param s string to process + * @return string the display, JShell package and wrapper class names removed + */ static String expunge(String s) { StringBuilder sb = new StringBuilder(); - for (String comp : prefixPattern.split(s)) { + for (String comp : PREFIX_PATTERN.split(s)) { sb.append(comp); } return sb.toString(); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteCodes.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteCodes.java index edb33f0bd38..e8deae7e73c 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteCodes.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteCodes.java @@ -47,8 +47,12 @@ public class RemoteCodes { public static final int RESULT_CORRALLED = 103; public static final int RESULT_KILLED = 104; + // String constants + public static final String REPL_PACKAGE = "REPL"; + public static final String REPL_CLASS_PREFIX = "$JShell$"; public static final String DOIT_METHOD_NAME = "do_it$"; - public static final String replClass = "\\$REPL(?\\d+)[A-Z]*"; - public static final Pattern prefixPattern = Pattern.compile("(REPL\\.)?" + replClass + "[\\$\\.]?"); - + public static final Pattern PREFIX_PATTERN = Pattern.compile( + "(" + REPL_PACKAGE + "\\.)?" + + "(?" + Pattern.quote(REPL_CLASS_PREFIX) + + "\\w+" + ")" + "[\\$\\.]?"); } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties index 34ef112a527..b70c6de2ac0 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties @@ -512,7 +512,7 @@ startup.feedback = \ /set format verbose errorpre '| ' \n\ /set format verbose errorpost '%n' \n\ \n\ -/set format verbose errorline '{pre} {err}' \n\ +/set format verbose errorline '{post}{pre} {err}' \n\ \n\ /set format verbose action 'created' added-primary \n\ /set format verbose action 'modified' modified-primary \n\ diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ClassTracker.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ClassTracker.java index 206aa94b86a..51af9abbc93 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ClassTracker.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ClassTracker.java @@ -27,6 +27,7 @@ package jdk.jshell; import java.util.Arrays; import java.util.HashMap; +import java.util.Objects; import com.sun.jdi.ReferenceType; /** @@ -82,6 +83,17 @@ class ClassTracker { } return rt; } + + @Override + public boolean equals(Object o) { + return o instanceof ClassInfo && + ((ClassInfo) o).className.equals(className); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.className); + } } ClassInfo classInfo(String className, byte[] bytes) { @@ -93,5 +105,4 @@ class ClassTracker { ClassInfo get(String className) { return map.get(className); } - } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/DeclarationSnippet.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/DeclarationSnippet.java index 8fc60cb749d..3902fbae3bb 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/DeclarationSnippet.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/DeclarationSnippet.java @@ -84,6 +84,6 @@ public abstract class DeclarationSnippet extends PersistentSnippet { @Override String importLine(JShell state) { - return "import static " + state.maps.classFullName(this) + "." + name() + ";\n"; + return "import static " + classFullName() + "." + name() + ";\n"; } } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java index 9a5c7538143..396396dec2a 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java @@ -100,10 +100,12 @@ public abstract class Diag { // *** Internal support *** /** - * Internal: If this is from a compile, extract the compilation Unit. + * Internal: If this is from a compile/analyze wrapped in an outer class, extract the snippet. * Otherwise null. */ - abstract Unit unitOrNull(); + Snippet snippetOrNull() { + return null; + } /** * This is an unreachable-statement error @@ -124,6 +126,7 @@ public abstract class Diag { */ boolean isResolutionError() { //TODO: try javac RESOLVE_ERROR flag - return getCode().startsWith("compiler.err.cant.resolve"); + return getCode().startsWith("compiler.err.cant.resolve") + || getCode().equals("compiler.err.cant.apply.symbol"); } } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/DiagList.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/DiagList.java index b0546fe5e12..7007a5f7f1a 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/DiagList.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/DiagList.java @@ -106,7 +106,10 @@ final class DiagList extends ArrayList { DiagList ofUnit(Unit u) { return this.stream() - .filter(d -> d.unitOrNull() == u) + .filter(d -> { + Snippet snn = d.snippetOrNull(); + return snn == u.snippet(); + }) .collect(Collectors.toCollection(() -> new DiagList())); } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java index 7e0e4b35392..961eafbf0c0 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jshell; import java.util.ArrayList; @@ -50,7 +49,6 @@ import java.io.StringWriter; import java.io.Writer; import java.util.LinkedHashSet; import java.util.Set; -import com.sun.tools.javac.util.Context; import jdk.jshell.ClassTracker.ClassInfo; import jdk.jshell.Key.ErroneousKey; import jdk.jshell.Key.MethodKey; @@ -68,7 +66,7 @@ import static java.util.stream.Collectors.toSet; import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN; import static jdk.jshell.Util.*; import static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME; -import static jdk.internal.jshell.remote.RemoteCodes.prefixPattern; +import static jdk.internal.jshell.remote.RemoteCodes.PREFIX_PATTERN; import static jdk.jshell.Snippet.SubKind.SINGLE_TYPE_IMPORT_SUBKIND; import static jdk.jshell.Snippet.SubKind.SINGLE_STATIC_IMPORT_SUBKIND; import static jdk.jshell.Snippet.SubKind.TYPE_IMPORT_ON_DEMAND_SUBKIND; @@ -339,18 +337,8 @@ class Eval { return declare(snip); } - private OuterWrap wrapInClass(String className, Set except, String userSource, Wrap guts, Collection plus) { - String imports = state.maps.packageAndImportsExcept(except, plus); - return OuterWrap.wrapInClass(state.maps.packageName(), className, imports, userSource, guts); - } - - OuterWrap wrapInClass(Snippet snip, Set except, Wrap guts, Collection plus) { - return wrapInClass(snip.className(), except, snip.source(), guts, plus); - } - private AnalyzeTask trialCompile(Wrap guts) { - OuterWrap outer = wrapInClass(REPL_DOESNOTMATTER_CLASS_NAME, - Collections.emptySet(), "", guts, null); + OuterWrap outer = state.outerMap.wrapInTrialClass(guts); return state.taskFactory.new AnalyzeTask(outer); } @@ -468,7 +456,7 @@ class Eval { if (si.status().isDefined) { if (si.isExecutable()) { try { - value = state.executionControl().commandInvoke(state.maps.classFullName(si)); + value = state.executionControl().commandInvoke(si.classFullName()); value = si.subKind().hasValue() ? expunge(value) : ""; @@ -504,37 +492,54 @@ class Eval { return events(c, outs, value, exception); } + private boolean interestingEvent(SnippetEvent e) { + return e.isSignatureChange() + || e.causeSnippet() == null + || e.status() != e.previousStatus() + || e.exception() != null; + } + private List events(Unit c, Collection outs, String value, Exception exception) { List events = new ArrayList<>(); events.add(c.event(value, exception)); events.addAll(outs.stream() .filter(u -> u != c) .map(u -> u.event(null, null)) + .filter(this::interestingEvent) .collect(Collectors.toList())); events.addAll(outs.stream() .flatMap(u -> u.secondaryEvents().stream()) + .filter(this::interestingEvent) .collect(Collectors.toList())); //System.err.printf("Events: %s\n", events); return events; } + private Set outerWrapSet(Collection units) { + return units.stream() + .map(u -> u.snippet().outerWrap()) + .collect(toSet()); + } + private Set compileAndLoad(Set ins) { if (ins.isEmpty()) { return ins; } Set replaced = new LinkedHashSet<>(); + // Loop until dependencies and errors are stable while (true) { state.debug(DBG_GEN, "compileAndLoad %s\n", ins); - ins.stream().forEach(u -> u.initialize(ins)); - AnalyzeTask at = state.taskFactory.new AnalyzeTask(ins); + ins.stream().forEach(u -> u.initialize()); + ins.stream().forEach(u -> u.setWrap(ins, ins)); + AnalyzeTask at = state.taskFactory.new AnalyzeTask(outerWrapSet(ins)); ins.stream().forEach(u -> u.setDiagnostics(at)); // corral any Snippets that need it AnalyzeTask cat; if (ins.stream().anyMatch(u -> u.corralIfNeeded(ins))) { // if any were corralled, re-analyze everything - cat = state.taskFactory.new AnalyzeTask(ins); + cat = state.taskFactory.new AnalyzeTask(outerWrapSet(ins)); ins.stream().forEach(u -> u.setCorralledDiagnostics(cat)); } else { cat = at; @@ -556,7 +561,7 @@ class Eval { legit.stream().forEach(u -> u.setWrap(ins, legit)); // generate class files for those capable - CompileTask ct = state.taskFactory.new CompileTask(legit); + CompileTask ct = state.taskFactory.new CompileTask(outerWrapSet(legit)); if (!ct.compile()) { // oy! compile failed because of recursive new unresolved if (legit.stream() @@ -572,8 +577,8 @@ class Eval { // load all new classes load(legit.stream() - .flatMap(u -> u.classesToLoad(ct.classInfoList(u))) - .collect(toList())); + .flatMap(u -> u.classesToLoad(ct.classInfoList(u.snippet().outerWrap()))) + .collect(toSet())); // attempt to redefine the remaining classes List toReplace = legit.stream() .filter(u -> !u.doRedefines()) @@ -607,7 +612,7 @@ class Eval { } } - private void load(List cil) { + private void load(Set cil) { if (!cil.isEmpty()) { state.executionControl().commandLoad(cil); } @@ -625,20 +630,14 @@ class Eval { StackTraceElement[] elems = new StackTraceElement[last + 1]; for (int i = 0; i <= last; ++i) { StackTraceElement r = raw[i]; - String rawKlass = r.getClassName(); - Matcher matcher = prefixPattern.matcher(rawKlass); - String num; - if (matcher.find() && (num = matcher.group("num")) != null) { - int end = matcher.end(); - if (rawKlass.charAt(end - 1) == '$') { - --end; - } - int id = Integer.parseInt(num); - Snippet si = state.maps.getSnippet(id); - String klass = expunge(rawKlass); + OuterSnippetsClassWrap outer = state.outerMap.getOuter(r.getClassName()); + if (outer != null) { + String klass = expunge(r.getClassName()); String method = r.getMethodName().equals(DOIT_METHOD_NAME) ? "" : r.getMethodName(); - String file = "#" + id; - int line = si.outerWrap().wrapLineToSnippetLine(r.getLineNumber() - 1) + 1; + int wln = r.getLineNumber() - 1; + int line = outer.wrapLineToSnippetLine(wln) + 1; + Snippet sn = outer.wrapLineToSnippet(wln); + String file = "#" + sn.id(); elems[i] = new StackTraceElement(klass, method, file, line); } else if (r.getFileName().equals("")) { elems[i] = new StackTraceElement(r.getClassName(), r.getMethodName(), null, r.getLineNumber()); @@ -654,7 +653,7 @@ class Eval { } private boolean isWrap(StackTraceElement ste) { - return prefixPattern.matcher(ste.getClassName()).find(); + return PREFIX_PATTERN.matcher(ste.getClassName()).find(); } private DiagList modifierDiagnostics(ModifiersTree modtree, @@ -714,11 +713,6 @@ class Eval { public String getMessage(Locale locale) { return message; } - - @Override - Unit unitOrNull() { - return null; - } } List list = new ArrayList<>(); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java index abaa5cbd5d5..f69ec57e797 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java @@ -36,6 +36,7 @@ import java.net.ServerSocket; import java.net.Socket; import com.sun.jdi.*; import java.io.EOFException; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -94,7 +95,7 @@ class ExecutionControl { } - boolean commandLoad(List cil) { + boolean commandLoad(Collection cil) { try { out.writeInt(CMD_LOAD); out.writeInt(cil.size()); @@ -122,7 +123,7 @@ class ExecutionControl { String result = in.readUTF(); return result; } - } catch (IOException | ClassNotFoundException ex) { + } catch (IOException | RuntimeException ex) { if (!env.connection().isRunning()) { env.shutdown(); } else { @@ -204,7 +205,7 @@ class ExecutionControl { } } - private boolean readAndReportExecutionResult() throws IOException, ClassNotFoundException, EvalException, UnresolvedReferenceException { + private boolean readAndReportExecutionResult() throws IOException, EvalException, UnresolvedReferenceException { int ok = in.readInt(); switch (ok) { case RESULT_SUCCESS: @@ -224,7 +225,7 @@ class ExecutionControl { case RESULT_CORRALLED: { int id = in.readInt(); StackTraceElement[] elems = readStackTrace(); - Snippet si = maps.getSnippet(id); + Snippet si = maps.getSnippetDeadOrAlive(id); throw new UnresolvedReferenceException((DeclarationSnippet) si, elems); } case RESULT_KILLED: { diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java index b261e5e67be..0cb2d05c7af 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java @@ -77,6 +77,7 @@ public class JShell implements AutoCloseable { final SnippetMaps maps; final KeyMap keyMap; + final OuterWrapMap outerMap; final TaskFactory taskFactory; final InputStream in; final PrintStream out; @@ -106,8 +107,8 @@ public class JShell implements AutoCloseable { this.idGenerator = b.idGenerator; this.maps = new SnippetMaps(this); - maps.setPackageName("REPL"); this.keyMap = new KeyMap(this); + this.outerMap = new OuterWrapMap(this); this.taskFactory = new TaskFactory(this); this.eval = new Eval(this); this.classTracker = new ClassTracker(this); @@ -563,7 +564,7 @@ public class JShell implements AutoCloseable { throw new IllegalArgumentException( messageFormat("jshell.exc.var.not.valid", snippet, snippet.status())); } - String value = executionControl().commandVarValue(maps.classFullName(snippet), snippet.name()); + String value = executionControl().commandVarValue(snippet.classFullName(), snippet.name()); return expunge(value); } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterImportSnippetWrap.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterImportSnippetWrap.java new file mode 100644 index 00000000000..8e336544943 --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterImportSnippetWrap.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.jshell; + +import java.util.IdentityHashMap; +import java.util.List; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +/** + * The outer wrap for a set of snippets wrapped in a generated class + * @author Robert Field + */ +public class OuterImportSnippetWrap extends OuterWrap { + + private final Snippet snippet; + + OuterImportSnippetWrap(Wrap wrap, Snippet snippet) { + super(wrap); + this.snippet = snippet; + } + + @Override + Diag wrapDiag(Diagnostic d) { + return new WrappedDiagnostic(d) { + + @Override + Snippet snippetOrNull() { + return snippet; + } + }; + } + + @Override + public String toString() { + return "OISW(" + w + ")"; + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterSnippetsClassWrap.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterSnippetsClassWrap.java new file mode 100644 index 00000000000..5a58ade38cc --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterSnippetsClassWrap.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.jshell; + +import java.util.LinkedHashMap; +import java.util.List; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import jdk.jshell.Wrap.CompoundWrap; + +/** + * The outer wrap for a set of snippets wrapped in a generated class + * @author Robert Field + */ +public class OuterSnippetsClassWrap extends OuterWrap { + + private final String className; + private final LinkedHashMap wrapToSnippet; + + OuterSnippetsClassWrap(String className, CompoundWrap w, List snippets, List wraps) { + super(w); + assert snippets == null || snippets.size() == wraps.size(); + this.className = className; + wrapToSnippet = new LinkedHashMap<>(); + for (int i = 0; i < snippets.size(); ++i) { + wrapToSnippet.put(wraps.get(i), snippets.get(i)); + } + } + + public Snippet wrapLineToSnippet(int wline) { + Wrap wrap = ((CompoundWrap)w).wrapLineToWrap(wline); + return wrapToSnippet.get(wrap); + } + + @Override + Diag wrapDiag(Diagnostic d) { + return new WrappedDiagnostic(d) { + + @Override + Snippet snippetOrNull() { + Wrap wrap = ((CompoundWrap) w).wrapIndexToWrap(diag.getPosition()); + Snippet sn = wrapToSnippet.get(wrap); + if (sn != null) { + return sn; + } else { + return super.snippetOrNull(); + } + } + }; + } + + int ordinal(Snippet sn) { + int i = 0; + for (Snippet si : wrapToSnippet.values()) { + if (si == sn) { + return i; + } + ++i; + } + return -1; + } + + @Override + public String className() { + return className; + } + + @Override + public String toString() { + return "OSCW(" + className + ":" + w + ")"; + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java index b44a7015020..f61d8b487d4 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015-2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,47 +25,23 @@ package jdk.jshell; -import jdk.jshell.Wrap.CompoundWrap; -import static jdk.jshell.Util.*; import java.util.Locale; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject; -import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN; +import jdk.internal.jshell.remote.RemoteCodes; +import static jdk.jshell.Util.*; +import static jdk.internal.jshell.remote.RemoteCodes.REPL_PACKAGE; /** * * @author Robert Field */ -final class OuterWrap implements GeneralWrap { +class OuterWrap implements GeneralWrap { - private final String packageName; - private final String className; - private final String userSource; - private final GeneralWrap w; - private final Wrap guts; + protected final Wrap w; - public static OuterWrap wrapInClass(String packageName, String className, - String imports, String userSource, Wrap guts) { - GeneralWrap kw = new CompoundWrap( - imports - + "class " + className + " {\n", - guts, - "}\n"); - return new OuterWrap(packageName, className, userSource, kw, guts); - } - - public static OuterWrap wrapImport(String userSource, Wrap guts) { - return new OuterWrap("", "", userSource, guts, guts); - } - - private OuterWrap(String packageName, String className, String userSource, - GeneralWrap w, Wrap guts) { - this.packageName = packageName; - this.className = className; - this.userSource = userSource; - this.w = w; - this.guts = guts; + OuterWrap(Wrap wrap) { + this.w = wrap; } @Override @@ -114,19 +90,28 @@ final class OuterWrap implements GeneralWrap { } public String className() { - return className; + return REPL_DOESNOTMATTER_CLASS_NAME; } public String classFullName() { - return packageName + "." + className; + return REPL_PACKAGE + "." + className(); } - public String getUserSource() { - return userSource; + @Override + public int hashCode() { + return className().hashCode(); } - Wrap guts() { - return guts; + @Override + public boolean equals(Object o) { + return (o instanceof OuterWrap) + ? className().equals(((OuterWrap) o).className()) + : false; + } + + @Override + public String toString() { + return "OW(" + w + ")"; } Diag wrapDiag(Diagnostic d) { @@ -135,7 +120,7 @@ final class OuterWrap implements GeneralWrap { class WrappedDiagnostic extends Diag { - private final Diagnostic diag; + final Diagnostic diag; WrappedDiagnostic(Diagnostic diag) { this.diag = diag; @@ -171,18 +156,6 @@ final class OuterWrap implements GeneralWrap { return expunge(diag.getMessage(locale)); } - @Override - Unit unitOrNull() { - JavaFileObject fo = diag.getSource(); - if (fo instanceof SourceMemoryJavaFileObject) { - SourceMemoryJavaFileObject sfo = (SourceMemoryJavaFileObject) fo; - if (sfo.getOrigin() instanceof Unit) { - return (Unit) sfo.getOrigin(); - } - } - return null; - } - @Override boolean isResolutionError() { if (!super.isResolutionError()) { @@ -190,7 +163,7 @@ final class OuterWrap implements GeneralWrap { } for (String line : diag.getMessage(PARSED_LOCALE).split("\\r?\\n")) { if (line.trim().startsWith("location:")) { - if (!line.contains(REPL_CLASS_PREFIX)) { + if (!line.contains(RemoteCodes.REPL_CLASS_PREFIX)) { // Resolution error must occur within a REPL class or it is not resolvable return false; } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java new file mode 100644 index 00000000000..1576ebe7725 --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.jshell; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.stream.Collectors; +import jdk.jshell.Wrap.CompoundWrap; +import static jdk.internal.jshell.remote.RemoteCodes.PREFIX_PATTERN; +import static jdk.internal.jshell.remote.RemoteCodes.REPL_CLASS_PREFIX; +import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME; +import static jdk.jshell.Util.asLetters; + +/** + * + * @author Robert Field + */ +public class OuterWrapMap { + + private final JShell state; + private final Map classOuters = new HashMap<>(); + + OuterWrapMap(JShell state) { + this.state = state; + } + + OuterSnippetsClassWrap getOuter(String className) { + Matcher matcher = PREFIX_PATTERN.matcher(className); + String cn; + if (matcher.find() && (cn = matcher.group("class")) != null) { + return classOuters.get(cn); + } + return null; + } + + private CompoundWrap wrappedInClass(String className, String imports, List wraps) { + List elems = new ArrayList<>(wraps.size() + 2); + elems.add(imports + + "class " + className + " {\n"); + elems.addAll(wraps); + elems.add("}\n"); + return new CompoundWrap(elems.toArray()); + } + + OuterWrap wrapInClass(Set except, Collection plus, + List snippets, List wraps) { + String imports = state.maps.packageAndImportsExcept(except, plus); + // className is unique to the set of snippets and their version (seq) + String className = REPL_CLASS_PREFIX + snippets.stream() + .sorted((sn1, sn2) -> sn1.key().index() - sn2.key().index()) + .map(sn -> "" + sn.key().index() + asLetters(sn.sequenceNumber())) + .collect(Collectors.joining("_")); + CompoundWrap w = wrappedInClass(className, imports, wraps); + OuterSnippetsClassWrap now = new OuterSnippetsClassWrap(className, w, snippets, wraps); + classOuters.put(className, now); + return now; + } + + OuterWrap wrapInTrialClass(Wrap wrap) { + String imports = state.maps.packageAndImportsExcept(null, null); + CompoundWrap w = wrappedInClass(REPL_DOESNOTMATTER_CLASS_NAME, imports, + Collections.singletonList(wrap)); + return new OuterWrap(w); + } + + OuterWrap wrapImport(Wrap guts, Snippet sn) { + return new OuterImportSnippetWrap(guts, sn); + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java index 5f5489b6a78..6669cf1803d 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java @@ -28,8 +28,6 @@ package jdk.jshell; import java.util.Collection; import java.util.Collections; import java.util.List; -import static jdk.jshell.Util.REPL_CLASS_PREFIX; -import static jdk.jshell.Util.asLetters; /** * A Snippet represents a snippet of Java source code as passed to @@ -503,7 +501,6 @@ public abstract class Snippet { private final SubKind subkind; private int seq; - private String className; private String id; private OuterWrap outer; private Status status; @@ -615,7 +612,6 @@ public abstract class Snippet { final void setSequenceNumber(int seq) { this.seq = seq; - this.className = REPL_CLASS_PREFIX + key().index() + asLetters(seq); } void setOuterWrap(OuterWrap outer) { @@ -653,7 +649,11 @@ public abstract class Snippet { } String className() { - return className; + return outer.className(); + } + + String classFullName() { + return outer.classFullName(); } /** diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java index 149a90e05c3..9d0a48505d8 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java @@ -38,8 +38,9 @@ import java.util.regex.Matcher; import java.util.stream.Stream; import static java.util.stream.Collectors.toList; -import static jdk.internal.jshell.remote.RemoteCodes.prefixPattern; +import static jdk.internal.jshell.remote.RemoteCodes.PREFIX_PATTERN; import static jdk.internal.jshell.debug.InternalDebugControl.DBG_DEP; +import static jdk.internal.jshell.remote.RemoteCodes.REPL_PACKAGE; /** * Maintain relationships between the significant entities: Snippets, @@ -48,7 +49,6 @@ import static jdk.internal.jshell.debug.InternalDebugControl.DBG_DEP; */ final class SnippetMaps { - private String packageName; private final List keyIndexToSnippet = new ArrayList<>(); private final Set snippets = new LinkedHashSet<>(); private final Map> dependencies = new HashMap<>(); @@ -81,6 +81,13 @@ final class SnippetMaps { } Snippet getSnippet(int ki) { + Snippet sn = getSnippetDeadOrAlive(ki); + return (sn != null && !sn.status().isActive) + ? null + : sn; + } + + Snippet getSnippetDeadOrAlive(int ki) { if (ki >= keyIndexToSnippet.size()) { return null; } @@ -91,21 +98,9 @@ final class SnippetMaps { return new ArrayList<>(snippets); } - void setPackageName(String n) { - packageName = n; - } - - String packageName() { - return packageName; - } - - String classFullName(Snippet sn) { - return packageName + "." + sn.className(); - } - String packageAndImportsExcept(Set except, Collection plus) { StringBuilder sb = new StringBuilder(); - sb.append("package ").append(packageName()).append(";\n"); + sb.append("package ").append(REPL_PACKAGE).append(";\n"); for (Snippet si : keyIndexToSnippet) { if (si != null && si.status().isDefined && (except == null || !except.contains(si.key()))) { sb.append(si.importLine(state)); @@ -137,7 +132,7 @@ final class SnippetMaps { } List deps = new ArrayList<>(); for (Integer dss : depset) { - Snippet dep = getSnippet(dss); + Snippet dep = getSnippetDeadOrAlive(dss); if (dep != null) { deps.add(dep); state.debug(DBG_DEP, "Found dependency %s -> %s\n", snip.name(), dep.name()); @@ -161,7 +156,7 @@ final class SnippetMaps { } String fullClassNameAndPackageToClass(String full, String pkg) { - Matcher mat = prefixPattern.matcher(full); + Matcher mat = PREFIX_PATTERN.matcher(full); if (mat.lookingAt()) { return full.substring(mat.end()); } @@ -195,6 +190,6 @@ final class SnippetMaps { private Stream importSnippets() { return state.keyMap.importKeys() .map(key -> (ImportSnippet)getSnippet(key)) - .filter(sn -> state.status(sn).isDefined); + .filter(sn -> sn != null && state.status(sn).isDefined); } } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index 45f9661d0bb..ca6b08612b9 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -211,11 +211,6 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { throw new InternalError(); } - private OuterWrap wrapInClass(Wrap guts) { - String imports = proc.maps.packageAndImportsExcept(null, null); - return OuterWrap.wrapInClass(proc.maps.packageName(), REPL_DOESNOTMATTER_CLASS_NAME, imports, "", guts); - } - private Tree.Kind guessKind(String code) { ParseTask pt = proc.taskFactory.new ParseTask(code); List units = pt.units(); @@ -258,13 +253,13 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { OuterWrap codeWrap; switch (guessKind(code)) { case IMPORT: - codeWrap = OuterWrap.wrapImport(null, Wrap.simpleWrap(code + "any.any")); + codeWrap = proc.outerMap.wrapImport(Wrap.simpleWrap(code + "any.any"), null); break; case METHOD: - codeWrap = wrapInClass(Wrap.classMemberWrap(code)); + codeWrap = proc.outerMap.wrapInTrialClass(Wrap.classMemberWrap(code)); break; default: - codeWrap = wrapInClass(Wrap.methodWrap(code)); + codeWrap = proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); break; } String requiredPrefix = identifier; @@ -946,7 +941,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { if (guessKind(code) == Kind.IMPORT) return null; - OuterWrap codeWrap = wrapInClass(Wrap.methodWrap(code)); + OuterWrap codeWrap = proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap); SourcePositions sp = at.trees().getSourcePositions(); CompilationUnitTree topLevel = at.firstCuTree(); @@ -1064,7 +1059,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { case INTERFACE: case ANNOTATION_TYPE: case VARIABLE: return null; default: - codeWrap = wrapInClass(Wrap.methodWrap(code)); + codeWrap = proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); break; } AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap); @@ -1104,10 +1099,10 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { case IMPORT: return new QualifiedNames(Collections.emptyList(), -1, true, false); case METHOD: - codeWrap = wrapInClass(Wrap.classMemberWrap(code)); + codeWrap = proc.outerMap.wrapInTrialClass(Wrap.classMemberWrap(code)); break; default: - codeWrap = wrapInClass(Wrap.methodWrap(code)); + codeWrap = proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); break; } AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java index 8ad7862c6b4..ce34f5f16a6 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,48 +148,22 @@ class TaskFactory { public String getMessage(Locale locale) { return expunge(d.getMessage(locale)); } - - @Override - Unit unitOrNull() { - return null; - } }; } } private class WrapSourceHandler implements SourceHandler { - final OuterWrap wrap; - - WrapSourceHandler(OuterWrap wrap) { - this.wrap = wrap; - } - @Override public JavaFileObject sourceToFileObject(MemoryFileManager fm, OuterWrap w) { return fm.createSourceFileObject(w, w.classFullName(), w.wrapped()); } - @Override - public Diag diag(Diagnostic d) { - return wrap.wrapDiag(d); - } - } - - private class UnitSourceHandler implements SourceHandler { - - @Override - public JavaFileObject sourceToFileObject(MemoryFileManager fm, Unit u) { - return fm.createSourceFileObject(u, - state.maps.classFullName(u.snippet()), - u.snippet().outerWrap().wrapped()); - } - @Override public Diag diag(Diagnostic d) { SourceMemoryJavaFileObject smjfo = (SourceMemoryJavaFileObject) d.getSource(); - Unit u = (Unit) smjfo.getOrigin(); - return u.snippet().outerWrap().wrapDiag(d); + OuterWrap w = (OuterWrap) smjfo.getOrigin(); + return w.wrapDiag(d); } } @@ -242,13 +216,12 @@ class TaskFactory { private final Iterable cuts; AnalyzeTask(final OuterWrap wrap) { - this(Stream.of(wrap), - new WrapSourceHandler(wrap), - "-XDshouldStopPolicy=FLOW", "-proc:none"); + this(Collections.singletonList(wrap)); } - AnalyzeTask(final Collection units) { - this(units.stream(), new UnitSourceHandler(), + AnalyzeTask(final Collection wraps) { + this(wraps.stream(), + new WrapSourceHandler(), "-XDshouldStopPolicy=FLOW", "-Xlint:unchecked", "-XaddExports:jdk.jshell/jdk.internal.jshell.remote=ALL-UNNAMED", "-proc:none"); } @@ -287,10 +260,10 @@ class TaskFactory { */ class CompileTask extends BaseTask { - private final Map> classObjs = new HashMap<>(); + private final Map> classObjs = new HashMap<>(); - CompileTask(Collection units) { - super(units.stream(), new UnitSourceHandler(), + CompileTask(final Collection wraps) { + super(wraps.stream(), new WrapSourceHandler(), "-Xlint:unchecked", "-XaddExports:jdk.jshell/jdk.internal.jshell.remote=ALL-UNNAMED", "-proc:none"); } @@ -302,8 +275,8 @@ class TaskFactory { } - List classInfoList(Unit u) { - List l = classObjs.get(u); + List classInfoList(OuterWrap w) { + List l = classObjs.get(w); if (l == null) return Collections.emptyList(); return l.stream() .map(fo -> state.classTracker.classInfo(fo.getName(), fo.getBytes())) @@ -315,11 +288,11 @@ class TaskFactory { //debug("listenForNewClassFile %s loc=%s kind=%s\n", className, location, kind); if (location == CLASS_OUTPUT) { state.debug(DBG_GEN, "Compiler generating class %s\n", className); - Unit u = ((sibling instanceof SourceMemoryJavaFileObject) - && (((SourceMemoryJavaFileObject) sibling).getOrigin() instanceof Unit)) - ? (Unit) ((SourceMemoryJavaFileObject) sibling).getOrigin() + OuterWrap w = ((sibling instanceof SourceMemoryJavaFileObject) + && (((SourceMemoryJavaFileObject) sibling).getOrigin() instanceof OuterWrap)) + ? (OuterWrap) ((SourceMemoryJavaFileObject) sibling).getOrigin() : null; - classObjs.compute(u, (k, v) -> (v == null)? new ArrayList<>() : v) + classObjs.compute(w, (k, v) -> (v == null)? new ArrayList<>() : v) .add(jfo); } } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java index f59d10b0d3a..c9fd4cedc59 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java @@ -162,18 +162,28 @@ class TreeDissector { return new Range(start, end); } - Tree firstClassMember() { - if (targetClass != null) { - //TODO: missing classes - for (Tree mem : targetClass.getMembers()) { - if (mem.getKind() == Tree.Kind.VARIABLE) { - return mem; - } - if (mem.getKind() == Tree.Kind.METHOD) { - MethodTree mt = (MethodTree) mem; - if (!isDoIt(mt.getName()) && !mt.getName().toString().equals("")) { + MethodTree method(MethodSnippet msn) { + if (targetClass == null) { + return null; + } + OuterWrap ow = msn.outerWrap(); + if (!(ow instanceof OuterSnippetsClassWrap)) { + return null; + } + int ordinal = ((OuterSnippetsClassWrap) ow).ordinal(msn); + if (ordinal < 0) { + return null; + } + int count = 0; + String name = msn.name(); + for (Tree mem : targetClass.getMembers()) { + if (mem.getKind() == Tree.Kind.METHOD) { + MethodTree mt = (MethodTree) mem; + if (mt.getName().toString().equals(name)) { + if (count == ordinal) { return mt; } + ++count; } } } @@ -244,8 +254,8 @@ class TreeDissector { return ei; } - String typeOfMethod() { - Tree unitTree = firstClassMember(); + String typeOfMethod(MethodSnippet msn) { + Tree unitTree = method(msn); if (unitTree instanceof JCMethodDecl) { JCMethodDecl mtree = (JCMethodDecl) unitTree; Type mt = types().erasure(mtree.type); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java index 538f34f5a24..e5892470440 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,7 @@ final class Unit { private final DiagList generatedDiagnostics; private int seq; - private int seqInitial; + private String classNameInitial; private Wrap activeGuts; private Status status; private Status prevStatus; @@ -95,7 +95,7 @@ final class Unit { this.generatedDiagnostics = generatedDiagnostics; this.seq = isNew? 0 : siOld.sequenceNumber(); - this.seqInitial = seq; + this.classNameInitial = isNew? "" : siOld.className(); this.prevStatus = (isNew || isDependency) ? si.status() : siOld.status(); @@ -136,28 +136,50 @@ final class Unit { return isDependency; } - boolean isNew() { - return isNew; - } - - void initialize(Collection working) { + void initialize() { isAttemptingCorral = false; dependenciesNeeded = false; toRedefine = null; // assure NPE if classToLoad not called activeGuts = si.guts(); markOldDeclarationOverwritten(); - setWrap(working, working); } - void setWrap(Collection except, Collection plus) { - si.setOuterWrap(isImport() - ? OuterWrap.wrapImport(si.source(), activeGuts) - : state.eval.wrapInClass(si, - except.stream().map(u -> u.snippet().key()).collect(toSet()), - activeGuts, - plus.stream().map(u -> u.snippet()) - .filter(sn -> sn != si) - .collect(toList()))); + // Set the outer wrap of our Snippet + void setWrap(Collection exceptUnit, Collection plusUnfiltered) { + if (isImport()) { + si.setOuterWrap(state.outerMap.wrapImport(activeGuts, si)); + } else { + // Collect Units for be wrapped together. Just this except for overloaded methods + List units; + if (snippet().kind() == Kind.METHOD) { + String name = ((MethodSnippet) snippet()).name(); + units = plusUnfiltered.stream() + .filter(u -> u.snippet().kind() == Kind.METHOD && + ((MethodSnippet) u.snippet()).name().equals(name)) + .collect(toList()); + } else { + units = Collections.singletonList(this); + } + // Keys to exclude from imports + Set except = exceptUnit.stream() + .map(u -> u.snippet().key()) + .collect(toSet()); + // Snippets to add to imports + Collection plus = plusUnfiltered.stream() + .filter(u -> !units.contains(u)) + .map(u -> u.snippet()) + .collect(toList()); + // Snippets to wrap in an outer + List snippets = units.stream() + .map(u -> u.snippet()) + .collect(toList()); + // Snippet wraps to wrap in an outer + List wraps = units.stream() + .map(u -> u.activeGuts) + .collect(toList()); + // Set the outer wrap for this snippet + si.setOuterWrap(state.outerMap.wrapInClass(except, plus, snippets, wraps)); + } } void setDiagnostics(AnalyzeTask ct) { @@ -302,11 +324,13 @@ final class Unit { private boolean sigChanged() { return (status.isDefined != prevStatus.isDefined) - || (seq != seqInitial && status.isDefined) + || (status.isDefined && !si.className().equals(classNameInitial)) || signatureChanged; } Stream effectedDependents() { + //System.err.printf("effectedDependents sigChanged=%b dependenciesNeeded=%b status=%s\n", + // sigChanged(), dependenciesNeeded, status); return sigChanged() || dependenciesNeeded || status == RECOVERABLE_NOT_DEFINED ? dependents() : Stream.empty(); @@ -361,7 +385,7 @@ final class Unit { if (replaceOldEvent != null) secondaryEvents.add(replaceOldEvent); // Defined methods can overwrite methods of other (equivalent) snippets - if (si.kind() == Kind.METHOD && status.isDefined) { + if (isNew && si.kind() == Kind.METHOD && status.isDefined) { MethodSnippet msi = (MethodSnippet)si; String oqpt = msi.qualifiedParameterTypes(); String nqpt = computeQualifiedParameterTypes(at, msi); @@ -405,7 +429,7 @@ final class Unit { } private String computeQualifiedParameterTypes(AnalyzeTask at, MethodSnippet msi) { - String rawSig = TreeDissector.createBySnippet(at, msi).typeOfMethod(); + String rawSig = TreeDissector.createBySnippet(at, msi).typeOfMethod(msi); String signature = expunge(rawSig); int paren = signature.lastIndexOf(')'); @@ -425,7 +449,9 @@ final class Unit { } List secondaryEvents() { - return secondaryEvents; + return secondaryEvents==null + ? Collections.emptyList() + : secondaryEvents; } @Override diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java index 8cc42150790..553e6c97fb3 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java @@ -30,7 +30,8 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; import javax.lang.model.element.Name; import static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME; -import static jdk.internal.jshell.remote.RemoteCodes.prefixPattern; +import static jdk.internal.jshell.remote.RemoteCodes.PREFIX_PATTERN; +import static jdk.internal.jshell.remote.RemoteCodes.REPL_CLASS_PREFIX; /** * Assorted shared utilities. @@ -38,8 +39,7 @@ import static jdk.internal.jshell.remote.RemoteCodes.prefixPattern; */ class Util { - static final String REPL_CLASS_PREFIX = "$REPL"; - static final String REPL_DOESNOTMATTER_CLASS_NAME = REPL_CLASS_PREFIX+"00DOESNOTMATTER"; + static final String REPL_DOESNOTMATTER_CLASS_NAME = REPL_CLASS_PREFIX+"DOESNOTMATTER"; static final Locale PARSED_LOCALE = Locale.ROOT; @@ -53,7 +53,7 @@ class Util { static String expunge(String s) { StringBuilder sb = new StringBuilder(); - for (String comp : prefixPattern.split(s)) { + for (String comp : PREFIX_PATTERN.split(s)) { sb.append(comp); } return sb.toString(); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java index 3dd39750cf2..873a0d1cce8 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java @@ -25,6 +25,8 @@ package jdk.jshell; +import java.util.Arrays; +import static java.util.stream.Collectors.joining; import static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME; /** @@ -237,6 +239,27 @@ abstract class Wrap implements GeneralWrap { return 0; } + Wrap wrapIndexToWrap(long wi) { + int before = 0; + Wrap w = null; + for (Object o : os) { + if (o instanceof String) { + String s = (String) o; + before += s.length(); + } else if (o instanceof Wrap) { + w = (Wrap) o; + int len = w.wrapped().length(); + if ((wi - before) <= len) { + //System.err.printf("Defer to wrap %s - wi: %d. before; %d -- %s >>> %s\n", + // w, wi, before, w.debugPos(wi - before), w.wrapped()); + return w; + } + before += len; + } + } + return w; + } + @Override public int wrapIndexToSnippetIndex(int wi) { int before = 0; @@ -286,6 +309,25 @@ abstract class Wrap implements GeneralWrap { return 0; } + Wrap wrapLineToWrap(int wline) { + int before = 0; + Wrap w = null; + for (Object o : os) { + if (o instanceof String) { + String s = (String) o; + before += countLines(s); + } else if (o instanceof Wrap) { + w = (Wrap) o; + int lns = countLines(w.wrapped()); + if ((wline - before) < lns) { + return w; + } + before += lns; + } + } + return w; + } + @Override public int wrapLineToSnippetLine(int wline) { int before = 0; @@ -315,7 +357,10 @@ abstract class Wrap implements GeneralWrap { return snlineLast; } - + @Override + public String toString() { + return "CompoundWrap(" + Arrays.stream(os).map(u -> u.toString()).collect(joining(",")) + ")"; + } } private static class RangeWrap extends Wrap { @@ -404,6 +449,10 @@ abstract class Wrap implements GeneralWrap { return lastSnline; } + @Override + public String toString() { + return "RangeWrap(" + range + ")"; + } } private static class NoWrap extends RangeWrap { diff --git a/langtools/test/jdk/jshell/ClassesTest.java b/langtools/test/jdk/jshell/ClassesTest.java index 058714fe438..a0848f12f1c 100644 --- a/langtools/test/jdk/jshell/ClassesTest.java +++ b/langtools/test/jdk/jshell/ClassesTest.java @@ -47,6 +47,7 @@ import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; import static jdk.jshell.Snippet.Status.DROPPED; import static jdk.jshell.Snippet.Status.REJECTED; import static jdk.jshell.Snippet.Status.OVERWRITTEN; +import static jdk.jshell.Snippet.Status.NONEXISTENT; import static jdk.jshell.Snippet.SubKind.*; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -83,7 +84,7 @@ public class ClassesTest extends KullaTesting { TypeDeclSnippet c1 = (TypeDeclSnippet) assertDeclareFail("class A { void f() { return g(); } }", "compiler.err.prob.found.req"); assertTypeDeclSnippet(c1, "A", REJECTED, CLASS_SUBKIND, 0, 2); TypeDeclSnippet c2 = classKey(assertEval("class A { int f() { return g(); } }", - ste(c1, REJECTED, RECOVERABLE_DEFINED, true, null))); + ste(c1, NONEXISTENT, RECOVERABLE_DEFINED, true, null))); assertTypeDeclSnippet(c2, "A", RECOVERABLE_DEFINED, CLASS_SUBKIND, 1, 0); assertDrop(c2, ste(c2, RECOVERABLE_DEFINED, DROPPED, true, null)); @@ -176,6 +177,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + //8154496: test3 update: sig change should false public void classesRedeclaration3() { Snippet a = classKey(assertEval("class A { }")); assertClasses(clazz(KullaTesting.ClassType.CLASS, "A")); @@ -190,7 +192,7 @@ public class ClassesTest extends KullaTesting { ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(test1, VALID, VALID, true, MAIN_SNIPPET), ste(test2, VALID, VALID, true, MAIN_SNIPPET), - ste(test3, VALID, VALID, false, MAIN_SNIPPET), + ste(test3, VALID, VALID, true, MAIN_SNIPPET), ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); assertClasses(clazz(KullaTesting.ClassType.INTERFACE, "A")); assertMethods(method("()A", "test"), method("(A)void", "test"), method("(int)void", "test")); @@ -201,8 +203,7 @@ public class ClassesTest extends KullaTesting { Snippet b = classKey(assertEval("class B extends A { }", added(RECOVERABLE_NOT_DEFINED))); Snippet a = classKey(assertEval("class A extends B { }", DiagCheck.DIAG_IGNORE, DiagCheck.DIAG_IGNORE, - added(RECOVERABLE_NOT_DEFINED), - ste(b, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, MAIN_SNIPPET))); + added(REJECTED))); /*** assertDeclareFail("class A extends B { }", "****", added(REJECTED), diff --git a/langtools/test/jdk/jshell/DropTest.java b/langtools/test/jdk/jshell/DropTest.java index 04e9fb2a4e5..d00003f4b98 100644 --- a/langtools/test/jdk/jshell/DropTest.java +++ b/langtools/test/jdk/jshell/DropTest.java @@ -57,10 +57,10 @@ public class DropTest extends KullaTesting { assertActiveKeys(); method = methodKey(assertEval("int mu() { return x * 4; }", - ste(MAIN_SNIPPET, DROPPED, RECOVERABLE_DEFINED, true, null), + added(RECOVERABLE_DEFINED), ste(clazz, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET))); assertEval("int x = 10;", "10", - ste(MAIN_SNIPPET, DROPPED, VALID, true, null), + added(VALID), ste(method, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET)); PersistentSnippet c0 = varKey(assertEval("C c0 = new C();")); assertEval("c0.v();", "\"#40\""); @@ -189,12 +189,11 @@ public class DropTest extends KullaTesting { assertDrop(c, DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, - ste(c, RECOVERABLE_NOT_DEFINED, DROPPED, false, null), - ste(d, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, c)); + ste(c, RECOVERABLE_NOT_DEFINED, DROPPED, false, null)); assertEval("interface A {}", null, null, - DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, - ste(a, DROPPED, VALID, true, null), - ste(b, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, MAIN_SNIPPET)); + DiagCheck.DIAG_OK, + DiagCheck.DIAG_ERROR, + added(VALID)); assertClasses(); assertActiveKeys(); } diff --git a/langtools/test/jdk/jshell/KullaTesting.java b/langtools/test/jdk/jshell/KullaTesting.java index 0ea4a622499..7c4224a27db 100644 --- a/langtools/test/jdk/jshell/KullaTesting.java +++ b/langtools/test/jdk/jshell/KullaTesting.java @@ -651,7 +651,7 @@ public class KullaTesting { DiagCheck.DIAG_WARNING, DiagCheck.DIAG_IGNORE, mainInfo, updates); SnippetEvent e = events.get(0); List diagnostics = getState().diagnostics(e.snippet()); - assertDiagnostic(input, diagnostics.get(0), expectedDiagnostic); + if (expectedDiagnostic != null) assertDiagnostic(input, diagnostics.get(0), expectedDiagnostic); return e.snippet(); } diff --git a/langtools/test/jdk/jshell/MethodsTest.java b/langtools/test/jdk/jshell/MethodsTest.java index a5ffcd383ba..6d0c3f4b4f9 100644 --- a/langtools/test/jdk/jshell/MethodsTest.java +++ b/langtools/test/jdk/jshell/MethodsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ public class MethodsTest extends KullaTesting { MethodSnippet m1 = (MethodSnippet) assertDeclareFail("void f() { return g(); }", "compiler.err.prob.found.req"); assertMethodDeclSnippet(m1, "f", "()void", REJECTED, 0, 2); MethodSnippet m2 = methodKey(assertEval("int f() { return g(); }", - ste(m1, REJECTED, RECOVERABLE_DEFINED, true, null))); + added(RECOVERABLE_DEFINED))); assertMethodDeclSnippet(m1, "f", "()void", REJECTED, 0, 2); assertMethodDeclSnippet(m2, "f", "()int", RECOVERABLE_DEFINED, 1, 0); } @@ -115,6 +115,26 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + /*** + public void methodOverloadDependent() { + assertEval("String m(String s) { return s + s; }"); + assertEval("String m(double d) { return m(\"#\" + d); }"); + assertEval("String m(int x) { return m(2.25 * x); }"); + assertEval("String m() { return m(3); }"); + assertMethods( + method("(String)String", "m"), + method("(double)String", "m"), + method("(int)String", "m"), + method("()String", "m") + ); + assertEval("m();", "\"#6.75#6.75\""); + assertEval("m(2);", "\"#4.5#4.5\""); + assertEval("m(3.14);", "\"#3.14#3.14\""); + assertEval("m(\"hi\");", "\"hihi\""); + assertActiveKeys(); + } + ***/ + public void methodsRedeclaration1() { Snippet x = methodKey(assertEval("int x() { return 10; }")); Snippet y = methodKey(assertEval("String y() { return \"\"; }")); @@ -149,8 +169,7 @@ public class MethodsTest extends KullaTesting { assertEval("double b() { return 3.14159; }", ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(b, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(c, VALID, VALID, false, MAIN_SNIPPET)); + ste(b, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); assertMethods(method("()int", "a"), method("()double", "b"), method("()double", "c")); assertEval("c();", "3.14159"); assertActiveKeys(); @@ -202,7 +221,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); assertDeclareFail("int f() {}", "compiler.err.missing.ret.stmt", - ste(MAIN_SNIPPET, REJECTED, REJECTED, false, null)); + added(REJECTED)); assertNumberOfActiveMethods(0); assertActiveKeys(); diff --git a/langtools/test/jdk/jshell/ReplaceTest.java b/langtools/test/jdk/jshell/ReplaceTest.java index 60807c09601..b631c4958c9 100644 --- a/langtools/test/jdk/jshell/ReplaceTest.java +++ b/langtools/test/jdk/jshell/ReplaceTest.java @@ -97,8 +97,7 @@ public class ReplaceTest extends KullaTesting { assertEval("mu() == 0.0;", "true"); assertEval("double x = 2.5;", ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(musn, VALID, VALID, false, MAIN_SNIPPET)); + ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); Collection meths = getState().methods(); assertEquals(meths.size(), 1); assertTrue(musn == meths.iterator().next(), "Identity must not change"); @@ -115,8 +114,7 @@ public class ReplaceTest extends KullaTesting { assertEval("d();", "1060.0"); assertEval("int a() { return 5; }", ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(b, VALID, VALID, false, MAIN_SNIPPET)); + ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); assertEval("d();", "1150.0"); assertActiveKeys(); } @@ -127,8 +125,7 @@ public class ReplaceTest extends KullaTesting { assertEval("m();", "7"); assertEval("class C { int x = 99; int f() { return x; } }", ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(c, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(m, VALID, VALID, false, MAIN_SNIPPET)); + ste(c, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); assertEval("m();", "99"); assertActiveKeys(); } @@ -140,8 +137,7 @@ public class ReplaceTest extends KullaTesting { assertEval("new A().a == 0.0;", "true"); assertEval("double x = 2.5;", ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(c, VALID, VALID, false, MAIN_SNIPPET)); + ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); Collection classes = getState().types(); assertEquals(classes.size(), 1); assertTrue(c == classes.iterator().next(), "Identity must not change"); @@ -157,8 +153,7 @@ public class ReplaceTest extends KullaTesting { assertEval("new A().a == 0.0;", "true"); assertEval("double x() { return 2.5; }", ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(c, VALID, VALID, false, MAIN_SNIPPET)); + ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); assertEval("x();", "2.5"); Collection classes = getState().types(); assertEquals(classes.size(), 1); @@ -875,18 +870,15 @@ public class ReplaceTest extends KullaTesting { MethodSnippet k1 = methodKey(assertEval(ms1, added(VALID))); VarSnippet xd = varKey(assertEval(xsd, ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(xi, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(k1, VALID, VALID, false, MAIN_SNIPPET))); + ste(xi, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); MethodSnippet k2 = methodKey(assertEval(ms2, ste(MAIN_SNIPPET, VALID, VALID, true, null), //TODO: technically, should be false ste(k1, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); VarSnippet xi2 = varKey(assertEval(xsi, ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(xd, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(k2, VALID, VALID, false, MAIN_SNIPPET))); + ste(xd, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); varKey(assertEval(xsd, ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(xi2, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(k2, VALID, VALID, false, MAIN_SNIPPET))); + ste(xi2, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); } } diff --git a/langtools/test/jdk/jshell/SnippetStatusListenerTest.java b/langtools/test/jdk/jshell/SnippetStatusListenerTest.java index 715b350a617..14ea0b956a7 100644 --- a/langtools/test/jdk/jshell/SnippetStatusListenerTest.java +++ b/langtools/test/jdk/jshell/SnippetStatusListenerTest.java @@ -65,7 +65,7 @@ public class SnippetStatusListenerTest extends KullaTesting { getState().unsubscribe(subscription1); assertDrop(f, DiagCheck.DIAG_IGNORE, DiagCheck.DIAG_IGNORE, ste(f, REJECTED, DROPPED, false, null)); - assertEval("void f() { }", ste(MAIN_SNIPPET, DROPPED, VALID, true, null)); + assertEval("void f() { }", added(VALID)); assertEvalException("throw new RuntimeException();"); assertEquals(listener1.getEvents(), events1, "Checking that unsubscribed listener does not get events"); diff --git a/langtools/test/jdk/jshell/SnippetTest.java b/langtools/test/jdk/jshell/SnippetTest.java index e3176c0b6c8..f9518ba0aee 100644 --- a/langtools/test/jdk/jshell/SnippetTest.java +++ b/langtools/test/jdk/jshell/SnippetTest.java @@ -142,8 +142,7 @@ public class SnippetTest extends KullaTesting { assertActiveKeys(); assertEval("double f() { return 0.0; }", ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(f, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(g, VALID, VALID, false, MAIN_SNIPPET)); + ste(f, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); assertKeys(method("()void", "g"), clazz(KullaTesting.ClassType.INTERFACE, "A"), method("()double", "f")); assertActiveKeys(); diff --git a/langtools/test/jdk/jshell/VariablesTest.java b/langtools/test/jdk/jshell/VariablesTest.java index 3a374a0b52c..35eda77cdcc 100644 --- a/langtools/test/jdk/jshell/VariablesTest.java +++ b/langtools/test/jdk/jshell/VariablesTest.java @@ -83,7 +83,7 @@ public class VariablesTest extends KullaTesting { public void testVarValue2() { VarSnippet v1 = (VarSnippet) assertDeclareFail("int a = 0.0;", "compiler.err.prob.found.req"); badVarValue(v1); - VarSnippet v2 = varKey(assertEval("int a = 0;", ste(v1, REJECTED, VALID, true, null))); + VarSnippet v2 = varKey(assertEval("int a = 0;", added(VALID))); assertDrop(v2, ste(MAIN_SNIPPET, VALID, DROPPED, true, null)); badVarValue(v2); } @@ -111,7 +111,7 @@ public class VariablesTest extends KullaTesting { VarSnippet v1 = (VarSnippet) assertDeclareFail("int a = 0.0;", "compiler.err.prob.found.req"); assertVariableDeclSnippet(v1, "a", "int", REJECTED, SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, 0, 1); VarSnippet v2 = varKey(assertEval("int a = 0;", - ste(v1, REJECTED, VALID, true, null))); + added(VALID))); assertVariableDeclSnippet(v2, "a", "int", VALID, SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, 0, 0); assertDrop(v2, ste(MAIN_SNIPPET, VALID, DROPPED, true, null)); assertVariableDeclSnippet(v2, "a", "int", DROPPED, SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, 0, 0); From 2e406416e029b4127425866c5dd154a0859281a7 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 25 Apr 2016 15:09:15 -0700 Subject: [PATCH 145/222] 8154213: clean up uses of boxed primitive constructors in the java.desktop module Reviewed-by: serb, psadhukhan --- make/CompileJavaModules.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index 4ce9cca25bf..d2404007848 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -99,7 +99,7 @@ java.datatransfer_COPY := flavormap.properties ################################################################################ java.desktop_ADD_JAVAC_FLAGS := -Xdoclint:all/protected,-reference \ - '-Xdoclint/package:java.*,javax.*' -Xlint:-deprecation + '-Xdoclint/package:java.*,javax.*' java.desktop_COPY := .gif .png .wav .txt .xml .css .pf java.desktop_CLEAN := iio-plugin.properties cursors.properties From 3f778b5b22c3d45fc4d0553f52b11a7d5fc546ff Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 25 Apr 2016 15:09:45 -0700 Subject: [PATCH 146/222] 8154213: clean up uses of boxed primitive constructors in the java.desktop module Reviewed-by: serb, psadhukhan --- .../tools/generatenimbus/UIProperty.java | 6 ++--- .../com/apple/eawt/_AppMenuBarHandler.java | 2 +- .../com/apple/laf/AquaComboBoxPopup.java | 2 +- .../apple/laf/AquaInternalFramePaneUI.java | 2 +- .../com/apple/laf/AquaLookAndFeel.java | 24 ++++++++--------- .../laf/AquaTabbedPaneCopyFromBasicUI.java | 4 +-- .../com/apple/laf/AquaUtilControlSize.java | 2 +- .../com/apple/laf/ScreenPopupFactory.java | 4 +-- .../macosx/classes/sun/font/CStrike.java | 8 +++--- .../classes/sun/lwawt/macosx/LWCToolkit.java | 6 ++--- .../sun/beans/decoder/NewElementHandler.java | 2 +- .../sun/imageio/plugins/bmp/BMPMetadata.java | 16 ++++++------ .../java/swing/plaf/gtk/GTKLookAndFeel.java | 2 +- .../com/sun/java/swing/plaf/gtk/Metacity.java | 2 +- .../classes/java/awt/font/TextAttribute.java | 2 +- .../classes/java/awt/font/TextMeasurer.java | 2 +- .../awt/image/renderable/ParameterBlock.java | 8 +++--- .../classes/javax/swing/JLayeredPane.java | 16 ++++++------ .../classes/javax/swing/JProgressBar.java | 2 +- .../share/classes/javax/swing/JTable.java | 2 +- .../javax/swing/SpinnerNumberModel.java | 15 ++++++----- .../share/classes/javax/swing/UIDefaults.java | 2 +- .../javax/swing/plaf/metal/OceanTheme.java | 6 ++--- .../javax/swing/text/JTextComponent.java | 6 ++--- .../javax/swing/text/NumberFormatter.java | 2 +- .../javax/swing/text/StyleConstants.java | 12 ++++----- .../classes/javax/swing/text/html/CSS.java | 26 +++++++++---------- .../javax/swing/text/rtf/RTFAttributes.java | 4 +-- .../sun/awt/image/PNGImageDecoder.java | 2 +- .../classes/sun/print/ServiceDialog.java | 12 ++++----- .../sun/print/PrintServiceLookupProvider.java | 2 +- 31 files changed, 102 insertions(+), 101 deletions(-) diff --git a/jdk/make/src/classes/build/tools/generatenimbus/UIProperty.java b/jdk/make/src/classes/build/tools/generatenimbus/UIProperty.java index 381db518284..943426c6881 100644 --- a/jdk/make/src/classes/build/tools/generatenimbus/UIProperty.java +++ b/jdk/make/src/classes/build/tools/generatenimbus/UIProperty.java @@ -54,13 +54,13 @@ class UIProperty extends UIDefault { return String.format(" d.put(\"%s%s\", \"%s\");\n", prefix, getName(), getValue()); case INT: - return String.format(" d.put(\"%s%s\", new Integer(%s));\n", + return String.format(" d.put(\"%s%s\", Integer.valueOf(%s));\n", prefix, getName(), getValue()); case FLOAT: - return String.format(" d.put(\"%s%s\", new Float(%sf));\n", + return String.format(" d.put(\"%s%s\", Float.valueOf(%sf));\n", prefix, getName(), getValue()); case DOUBLE: - return String.format(" d.put(\"%s%s\", new Double(%s));\n", + return String.format(" d.put(\"%s%s\", Double.valueOf(%s));\n", prefix, getName(), getValue()); case COLOR: return String.format(" addColor(d, \"%s%s\", %s);\n", diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/eawt/_AppMenuBarHandler.java b/jdk/src/java.desktop/macosx/classes/com/apple/eawt/_AppMenuBarHandler.java index 3a132f25595..027cbcf67e6 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/eawt/_AppMenuBarHandler.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/eawt/_AppMenuBarHandler.java @@ -83,7 +83,7 @@ class _AppMenuBarHandler { // if we have no foreground frames, then we have to "kick" the menubar final JFrame pingFrame = new JFrame(); - pingFrame.getRootPane().putClientProperty("Window.alpha", new Float(0.0f)); + pingFrame.getRootPane().putClientProperty("Window.alpha", Float.valueOf(0.0f)); pingFrame.setUndecorated(true); pingFrame.setVisible(true); pingFrame.toFront(); diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java index 332cb7e46ff..88faf6b06e8 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java @@ -58,7 +58,7 @@ class AquaComboBoxPopup extends BasicComboPopup { updateContents(false); // TODO: CPlatformWindow? - putClientProperty(CPlatformWindow.WINDOW_FADE_OUT, new Integer(150)); + putClientProperty(CPlatformWindow.WINDOW_FADE_OUT, Integer.valueOf(150)); } public void updateContents(final boolean remove) { diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFramePaneUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFramePaneUI.java index 1534d6d80c7..e12033fceb5 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFramePaneUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFramePaneUI.java @@ -91,7 +91,7 @@ public class AquaInternalFramePaneUI extends BasicDesktopPaneUI implements Mouse JComponent getDock() { if (fDock == null) { fDock = new Dock(desktop); - desktop.add(fDock, new Integer(399)); // Just below the DRAG_LAYER + desktop.add(fDock, Integer.valueOf(399)); // Just below the DRAG_LAYER } return fDock; } diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java index f04d42de03b..6694dd4c292 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java @@ -416,7 +416,7 @@ public class AquaLookAndFeel extends BasicLookAndFeel { "Button.select", selected, "Button.border",(LazyValue) t -> AquaButtonBorder.getDynamicButtonBorder(), "Button.font", controlFont, - "Button.textIconGap", new Integer(4), + "Button.textIconGap", Integer.valueOf(4), "Button.textShiftOffset", zero, // radar 3308129 - aqua doesn't move images when pressed. "Button.focusInputMap", controlFocusInputMap, "Button.margin", new InsetsUIResource(0, 2, 0, 2), @@ -635,8 +635,8 @@ public class AquaLookAndFeel extends BasicLookAndFeel { //"Menu.checkIcon", emptyCheckIcon, // A non-drawing GlyphIcon to make the spacing consistent "Menu.arrowIcon",(LazyValue) t -> AquaImageFactory.getMenuArrowIcon(), "Menu.consumesTabs", Boolean.TRUE, - "Menu.menuPopupOffsetY", new Integer(1), - "Menu.submenuPopupOffsetY", new Integer(-4), + "Menu.menuPopupOffsetY", Integer.valueOf(1), + "Menu.submenuPopupOffsetY", Integer.valueOf(-4), "MenuBar.font", menuFont, "MenuBar.background", menuBackgroundColor, // not a menu item, not selected @@ -694,7 +694,7 @@ public class AquaLookAndFeel extends BasicLookAndFeel { "OptionPane.informationSound", null, // Info and Plain "OptionPane.questionSound", null, "OptionPane.warningSound", null, - "OptionPane.buttonClickThreshhold", new Integer(500), + "OptionPane.buttonClickThreshhold", Integer.valueOf(500), "OptionPane.yesButtonMnemonic", "", "OptionPane.noButtonMnemonic", "", "OptionPane.okButtonMnemonic", "", @@ -717,7 +717,7 @@ public class AquaLookAndFeel extends BasicLookAndFeel { "PasswordField.caretBlinkRate", textCaretBlinkRate, "PasswordField.border", textFieldBorder, "PasswordField.margin", zeroInsets, - "PasswordField.echoChar", new Character((char)0x25CF), + "PasswordField.echoChar", Character.valueOf((char)0x25CF), "PasswordField.capsLockIconColor", textPasswordFieldCapsLockIconColor, "PopupMenu.font", menuFont, @@ -736,7 +736,7 @@ public class AquaLookAndFeel extends BasicLookAndFeel { "ProgressBar.selectionForeground", black, "ProgressBar.selectionBackground", white, "ProgressBar.border", new BorderUIResource(BorderFactory.createEmptyBorder()), - "ProgressBar.repaintInterval", new Integer(20), + "ProgressBar.repaintInterval", Integer.valueOf(20), "RadioButton.background", controlBackgroundColor, "RadioButton.foreground", black, @@ -772,7 +772,7 @@ public class AquaLookAndFeel extends BasicLookAndFeel { "ScrollBar.border", null, "ScrollBar.focusInputMap", aquaKeyBindings.getScrollBarInputMap(), "ScrollBar.focusInputMap.RightToLeft", aquaKeyBindings.getScrollBarRightToLeftInputMap(), - "ScrollBar.width", new Integer(16), + "ScrollBar.width", Integer.valueOf(16), "ScrollBar.background", white, "ScrollBar.foreground", black, @@ -816,7 +816,7 @@ public class AquaLookAndFeel extends BasicLookAndFeel { //"SplitPane.shadow", table.get("controlShadow"), "SplitPane.background", panelBackgroundColor, "SplitPane.border", scollListBorder, - "SplitPane.dividerSize", new Integer(9), //$ + "SplitPane.dividerSize", Integer.valueOf(9), //$ "SplitPaneDivider.border", null, // AquaSplitPaneDividerUI draws it "SplitPaneDivider.horizontalGradientVariant",(LazyValue) t -> AquaSplitPaneDividerUI.getHorizontalSplitDividerGradientVariant(), @@ -833,7 +833,7 @@ public class AquaLookAndFeel extends BasicLookAndFeel { //"TabbedPane.darkShadow", table.get("controlDkShadow"), //"TabbedPane.focus", table.get("controlText"), "TabbedPane.opaque", useOpaqueComponents, - "TabbedPane.textIconGap", new Integer(4), + "TabbedPane.textIconGap", Integer.valueOf(4), "TabbedPane.tabInsets", new InsetsUIResource(0, 10, 3, 10), // Label within tab (top, left, bottom, right) //"TabbedPane.rightTabInsets", new InsetsUIResource(0, 10, 3, 10), // Label within tab (top, left, bottom, right) "TabbedPane.leftTabInsets", new InsetsUIResource(0, 10, 3, 10), // Label within tab @@ -973,9 +973,9 @@ public class AquaLookAndFeel extends BasicLookAndFeel { "Tree.selectionBorderColor", selectionBackground, // match the background so it looks like we don't draw anything "Tree.editorBorderSelectionColor", null, // The EditTextFrame provides its own border // "Tree.editorBorder", textFieldBorder, // If you still have Sun bug 4376328 in DefaultTreeCellEditor, it has to have the same insets as TextField.border - "Tree.leftChildIndent", new Integer(7),//$ - "Tree.rightChildIndent", new Integer(13),//$ - "Tree.rowHeight", new Integer(19),// iconHeight + 3, to match finder - a zero would have the renderer decide, except that leaves the icons touching + "Tree.leftChildIndent", Integer.valueOf(7),//$ + "Tree.rightChildIndent", Integer.valueOf(13),//$ + "Tree.rowHeight", Integer.valueOf(19),// iconHeight + 3, to match finder - a zero would have the renderer decide, except that leaves the icons touching "Tree.scrollsOnExpand", Boolean.FALSE, "Tree.openIcon",(LazyValue) t -> AquaImageFactory.getTreeOpenFolderIcon(), // Open folder icon "Tree.closedIcon",(LazyValue) t -> AquaImageFactory.getTreeFolderIcon(), // Closed folder icon diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java index d85ed9e8f67..ad78bc26ca3 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java @@ -521,7 +521,7 @@ public class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements Swing } // [2165820] Mac OS X change: mnemonics need to be triggered with ctrl-option, not just option. mnemonicInputMap.put(KeyStroke.getKeyStroke(mnemonic, Event.ALT_MASK | Event.CTRL_MASK), "setSelectedIndex"); - mnemonicToIndexMap.put(new Integer(mnemonic), new Integer(index)); + mnemonicToIndexMap.put(Integer.valueOf(mnemonic), Integer.valueOf(index)); } /** @@ -2084,7 +2084,7 @@ public class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements Swing if (mnemonic >= 'a' && mnemonic <= 'z') { mnemonic -= ('a' - 'A'); } - final Integer index = ui.mnemonicToIndexMap.get(new Integer(mnemonic)); + final Integer index = ui.mnemonicToIndexMap.get(Integer.valueOf(mnemonic)); if (index != null && pane.isEnabledAt(index.intValue())) { pane.setSelectedIndex(index.intValue()); } diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaUtilControlSize.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaUtilControlSize.java index 2acc1eaedcf..999d24a7886 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaUtilControlSize.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaUtilControlSize.java @@ -268,7 +268,7 @@ public class AquaUtilControlSize { public SizeVariant alterFontSize(final float newSize) { final float oldSize = fontSize == null ? 0.0f : fontSize.floatValue(); - fontSize = new Float(newSize + oldSize); + fontSize = newSize + oldSize; return this; } diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/ScreenPopupFactory.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/ScreenPopupFactory.java index bb2c0f1081b..b08b890aa2b 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/ScreenPopupFactory.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/ScreenPopupFactory.java @@ -32,8 +32,8 @@ import sun.lwawt.macosx.CPlatformWindow; import sun.swing.SwingAccessor; class ScreenPopupFactory extends PopupFactory { - static final Float TRANSLUCENT = new Float(248f/255f); - static final Float OPAQUE = new Float(1.0f); + static final Float TRANSLUCENT = 248f/255f; + static final Float OPAQUE = 1.0f; boolean fIsActive = true; diff --git a/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java b/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java index c50533a5947..ed3838886c9 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java @@ -386,7 +386,7 @@ public final class CStrike extends PhysicalStrike { if (generalCache == null) { return 0L; } - final Long value = generalCache.get(new Integer(index)); + final Long value = generalCache.get(Integer.valueOf(index)); if (value == null) { return 0L; } @@ -415,7 +415,7 @@ public final class CStrike extends PhysicalStrike { generalCache = new HashMap(); } - generalCache.put(new Integer(index), Long.valueOf(value)); + generalCache.put(Integer.valueOf(index), Long.valueOf(value)); } public synchronized void dispose() { @@ -526,7 +526,7 @@ public final class CStrike extends PhysicalStrike { } if (generalCache == null) return 0; - final Float value = generalCache.get(new Integer(index)); + final Float value = generalCache.get(Integer.valueOf(index)); if (value == null) return 0; return value.floatValue(); } @@ -553,7 +553,7 @@ public final class CStrike extends PhysicalStrike { generalCache = new HashMap(); } - generalCache.put(new Integer(index), new Float(value)); + generalCache.put(Integer.valueOf(index), Float.valueOf(value)); } private static class SparseBitShiftingTwoLayerArray { diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index f0bf99c7321..309bc8ca8b1 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -378,9 +378,9 @@ public final class LWCToolkit extends LWToolkit { // These DnD properties must be set, otherwise Swing ends up spewing NPEs // all over the place. The values came straight off of MToolkit. - desktopProperties.put("DnD.Autoscroll.initialDelay", new Integer(50)); - desktopProperties.put("DnD.Autoscroll.interval", new Integer(50)); - desktopProperties.put("DnD.Autoscroll.cursorHysteresis", new Integer(5)); + desktopProperties.put("DnD.Autoscroll.initialDelay", Integer.valueOf(50)); + desktopProperties.put("DnD.Autoscroll.interval", Integer.valueOf(50)); + desktopProperties.put("DnD.Autoscroll.cursorHysteresis", Integer.valueOf(5)); desktopProperties.put("DnD.isDragImageSupported", Boolean.TRUE); diff --git a/jdk/src/java.desktop/share/classes/com/sun/beans/decoder/NewElementHandler.java b/jdk/src/java.desktop/share/classes/com/sun/beans/decoder/NewElementHandler.java index 69fbdce51dd..f753e04e83a 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/beans/decoder/NewElementHandler.java +++ b/jdk/src/java.desktop/share/classes/com/sun/beans/decoder/NewElementHandler.java @@ -42,7 +42,7 @@ import java.util.List; * <new class="java.lang.Long"> * <string>10</string> * </new> - * is equivalent to {@code new Long("10")} in Java code. + * is equivalent to {@code Long.valueOf("10")} in Java code. *

    The following attributes are supported: *

    *
    class diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java index d955c5f593c..4510882ad4b 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java @@ -128,7 +128,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { addChildNode(root, "BMPVersion", bmpVersion); addChildNode(root, "Width", width); addChildNode(root, "Height", height); - addChildNode(root, "BitsPerPixel", new Short(bitsPerPixel)); + addChildNode(root, "BitsPerPixel", Short.valueOf(bitsPerPixel)); addChildNode(root, "Compression", compression); addChildNode(root, "ImageSize", imageSize); @@ -172,12 +172,12 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { red = palette[j++] & 0xff; green = palette[j++] & 0xff; blue = palette[j++] & 0xff; - addChildNode(entry, "Red", new Byte((byte)red)); - addChildNode(entry, "Green", new Byte((byte)green)); - addChildNode(entry, "Blue", new Byte((byte)blue)); + addChildNode(entry, "Red", Byte.valueOf((byte)red)); + addChildNode(entry, "Green", Byte.valueOf((byte)green)); + addChildNode(entry, "Blue", Byte.valueOf((byte)blue)); if (numComps == 4) addChildNode(entry, "Alpha", - new Byte((byte)(palette[j++] & 0xff))); + Byte.valueOf((byte)(palette[j++] & 0xff))); } } @@ -284,9 +284,9 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { private void addXYZPoints(IIOMetadataNode root, String name, double x, double y, double z) { IIOMetadataNode node = addChildNode(root, name, null); - addChildNode(node, "X", new Double(x)); - addChildNode(node, "Y", new Double(y)); - addChildNode(node, "Z", new Double(z)); + addChildNode(node, "X", Double.valueOf(x)); + addChildNode(node, "Y", Double.valueOf(y)); + addChildNode(node, "Z", Double.valueOf(z)); } private IIOMetadataNode addChildNode(IIOMetadataNode root, diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index f568f6a4bae..be422a6275b 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -379,7 +379,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { } Insets zeroInsets = new InsetsUIResource(0, 0, 0, 0); - Double defaultCaretAspectRatio = new Double(0.025); + Double defaultCaretAspectRatio = Double.valueOf(0.025); Color caretColor = table.getColor("caretColor"); Color controlText = table.getColor("controlText"); diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java index 3a0342792b3..b8b77f5ec93 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java @@ -185,7 +185,7 @@ class Metacity implements SynthConstants { getIntAttr(child, "bottom", 0), getIntAttr(child, "right", 0)); } else if ("aspect_ratio".equals(name)) { - value = new Float(getFloatAttr(child, "value", 1.0F)); + value = Float.valueOf(getFloatAttr(child, "value", 1.0F)); } else { logError(themeName, "Unknown Metacity frame geometry value type: "+name); } diff --git a/jdk/src/java.desktop/share/classes/java/awt/font/TextAttribute.java b/jdk/src/java.desktop/share/classes/java/awt/font/TextAttribute.java index 238dcb988f9..c9ae83659f6 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/font/TextAttribute.java +++ b/jdk/src/java.desktop/share/classes/java/awt/font/TextAttribute.java @@ -79,7 +79,7 @@ import jdk.internal.misc.SharedSecrets; * will be ignored. *
  • The identity of the value does not matter, only the actual * value. For example, {@code TextAttribute.WEIGHT_BOLD} and - * {@code new Float(2.0)} + * {@code Float.valueOf(2.0f)} * indicate the same {@code WEIGHT}. *
  • Attribute values of type {@code Number} (used for * {@code WEIGHT}, {@code WIDTH}, {@code POSTURE}, diff --git a/jdk/src/java.desktop/share/classes/java/awt/font/TextMeasurer.java b/jdk/src/java.desktop/share/classes/java/awt/font/TextMeasurer.java index 4511d0eab15..5f47384697a 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/font/TextMeasurer.java +++ b/jdk/src/java.desktop/share/classes/java/awt/font/TextMeasurer.java @@ -105,7 +105,7 @@ public final class TextMeasurer implements Cloneable { String s = System.getProperty("estLines"); if (s != null) { try { - Float f = new Float(s); + Float f = Float.valueOf(s); EST_LINES = f.floatValue(); } catch(NumberFormatException e) { diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/renderable/ParameterBlock.java b/jdk/src/java.desktop/share/classes/java/awt/image/renderable/ParameterBlock.java index bfbaf5e1b2a..f9a3a2d2058 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/image/renderable/ParameterBlock.java +++ b/jdk/src/java.desktop/share/classes/java/awt/image/renderable/ParameterBlock.java @@ -392,7 +392,7 @@ public class ParameterBlock implements Cloneable, Serializable { * the specified parameter. */ public ParameterBlock add(float f) { - return add(new Float(f)); + return add(Float.valueOf(f)); } /** @@ -403,7 +403,7 @@ public class ParameterBlock implements Cloneable, Serializable { * the specified parameter. */ public ParameterBlock add(double d) { - return add(new Double(d)); + return add(Double.valueOf(d)); } /** @@ -521,7 +521,7 @@ public class ParameterBlock implements Cloneable, Serializable { * the specified parameter. */ public ParameterBlock set(float f, int index) { - return set(new Float(f), index); + return set(Float.valueOf(f), index); } /** @@ -537,7 +537,7 @@ public class ParameterBlock implements Cloneable, Serializable { * the specified parameter. */ public ParameterBlock set(double d, int index) { - return set(new Double(d), index); + return set(Double.valueOf(d), index); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JLayeredPane.java b/jdk/src/java.desktop/share/classes/javax/swing/JLayeredPane.java index 3d561b99bef..6de8a0bd750 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JLayeredPane.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JLayeredPane.java @@ -98,7 +98,7 @@ import javax.accessibility.*; *
      *     layeredPane.add(child, JLayeredPane.DEFAULT_LAYER);
      * or
    - *     layeredPane.add(child, new Integer(10));
    + *     layeredPane.add(child, Integer.valueOf.valueOf(10));
      * 
    * The layer attribute can also be set on a Component by calling
      *     layeredPaneParent.setLayer(child, 10)
    @@ -162,23 +162,23 @@ import javax.accessibility.*; @SuppressWarnings("serial") public class JLayeredPane extends JComponent implements Accessible { /// Watch the values in getObjectForLayer() - /** Convenience object defining the Default layer. Equivalent to new Integer(0).*/ + /** Convenience object defining the Default layer. Equivalent to Integer.valueOf(0).*/ public static final Integer DEFAULT_LAYER = 0; - /** Convenience object defining the Palette layer. Equivalent to new Integer(100).*/ + /** Convenience object defining the Palette layer. Equivalent to Integer.valueOf(100).*/ public static final Integer PALETTE_LAYER = 100; - /** Convenience object defining the Modal layer. Equivalent to new Integer(200).*/ + /** Convenience object defining the Modal layer. Equivalent to Integer.valueOf(200).*/ public static final Integer MODAL_LAYER = 200; - /** Convenience object defining the Popup layer. Equivalent to new Integer(300).*/ + /** Convenience object defining the Popup layer. Equivalent to Integer.valueOf(300).*/ public static final Integer POPUP_LAYER = 300; - /** Convenience object defining the Drag layer. Equivalent to new Integer(400).*/ + /** Convenience object defining the Drag layer. Equivalent to Integer.valueOf(400).*/ public static final Integer DRAG_LAYER = 400; /** Convenience object defining the Frame Content layer. * This layer is normally only use to position the contentPane and menuBar * components of JFrame. - * Equivalent to new Integer(-30000). + * Equivalent to Integer.valueOf(-30000). * @see JFrame */ - public static final Integer FRAME_CONTENT_LAYER = new Integer(-30000); + public static final Integer FRAME_CONTENT_LAYER = -30000; /** Bound property */ public static final String LAYER_PROPERTY = "layeredContainerLayer"; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JProgressBar.java b/jdk/src/java.desktop/share/classes/javax/swing/JProgressBar.java index 3504f2ef16a..216b18f4b19 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JProgressBar.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JProgressBar.java @@ -478,7 +478,7 @@ public class JProgressBar extends JComponent implements SwingConstants, Accessib if (format == null) { format = NumberFormat.getPercentInstance(); } - return format.format(new Double(getPercentComplete())); + return format.format(Double.valueOf(getPercentComplete())); } } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java index 9ca12ea6ee1..ee53fbffd91 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java @@ -81,7 +81,7 @@ import sun.swing.PrintingStatus; * TableModel dataModel = new AbstractTableModel() { * public int getColumnCount() { return 10; } * public int getRowCount() { return 10;} - * public Object getValueAt(int row, int col) { return new Integer(row*col); } + * public Object getValueAt(int row, int col) { return Integer.valueOf(row*col); } * }; * JTable table = new JTable(dataModel); * JScrollPane scrollpane = new JScrollPane(table); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/SpinnerNumberModel.java b/jdk/src/java.desktop/share/classes/javax/swing/SpinnerNumberModel.java index 1d7fa9dec20..3fbd668bb80 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/SpinnerNumberModel.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/SpinnerNumberModel.java @@ -51,10 +51,10 @@ import java.io.Serializable; * range zero to one hundred, with * fifty as the initial value, one could write: *
    - * Integer value = new Integer(50);
    - * Integer min = new Integer(0);
    - * Integer max = new Integer(100);
    - * Integer step = new Integer(1);
    + * Integer value = Integer.valueOf(50);
    + * Integer min = Integer.valueOf(0);
    + * Integer max = Integer.valueOf(100);
    + * Integer step = Integer.valueOf(1);
      * SpinnerNumberModel model = new SpinnerNumberModel(value, min, max, step);
      * int fifty = model.getNumber().intValue();
      * 
    @@ -175,7 +175,8 @@ public class SpinnerNumberModel extends AbstractSpinnerModel implements Serializ * minimum <= value <= maximum */ public SpinnerNumberModel(double value, double minimum, double maximum, double stepSize) { - this(new Double(value), new Double(minimum), new Double(maximum), new Double(stepSize)); + this(Double.valueOf(value), Double.valueOf(minimum), + Double.valueOf(maximum), Double.valueOf(stepSize)); } @@ -337,10 +338,10 @@ public class SpinnerNumberModel extends AbstractSpinnerModel implements Serializ if ((value instanceof Float) || (value instanceof Double)) { double v = value.doubleValue() + (stepSize.doubleValue() * (double)dir); if (value instanceof Double) { - newValue = new Double(v); + newValue = Double.valueOf(v); } else { - newValue = new Float(v); + newValue = Float.valueOf((float)v); } } else { long v = value.longValue() + (stepSize.longValue() * (long)dir); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/UIDefaults.java b/jdk/src/java.desktop/share/classes/javax/swing/UIDefaults.java index 1955407b75a..2ad447e6a18 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/UIDefaults.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/UIDefaults.java @@ -120,7 +120,7 @@ public class UIDefaults extends Hashtable Object[] uiDefaults = { "Font", new Font("Dialog", Font.BOLD, 12), "Color", Color.red, - "five", new Integer(5) + "five", Integer.valueOf(5) } UIDefaults myDefaults = new UIDefaults(uiDefaults); * diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/OceanTheme.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/OceanTheme.java index d37c57076b9..b19632ff141 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/OceanTheme.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/OceanTheme.java @@ -134,7 +134,7 @@ public class OceanTheme extends DefaultMetalTheme { new BorderUIResource.LineBorderUIResource(getPrimary1()); // .30 0 DDE8F3 white secondary2 java.util.List buttonGradient = Arrays.asList( - new Object[] {new Float(.3f), new Float(0f), + new Object[] {Float.valueOf(.3f), Float.valueOf(0f), new ColorUIResource(0xDDE8F3), getWhite(), getSecondary2() }); // Other possible properties that aren't defined: @@ -150,7 +150,7 @@ public class OceanTheme extends DefaultMetalTheme { Object directoryIcon = getIconResource("icons/ocean/directory.gif"); Object fileIcon = getIconResource("icons/ocean/file.gif"); java.util.List sliderGradient = Arrays.asList(new Object[] { - new Float(.3f), new Float(.2f), + Float.valueOf(.3f), Float.valueOf(.2f), c8ddf2, getWhite(), new ColorUIResource(SECONDARY2) }); Object[] defaults = new Object[] { @@ -192,7 +192,7 @@ public class OceanTheme extends DefaultMetalTheme { "Menu.opaque", Boolean.FALSE, "MenuBar.gradient", Arrays.asList(new Object[] { - new Float(1f), new Float(0f), + Float.valueOf(1f), Float.valueOf(0f), getWhite(), dadada, new ColorUIResource(dadada) }), "MenuBar.borderColor", cccccc, diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java index 3d31a0d1936..ff28193c3e8 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java @@ -2580,7 +2580,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @param e the DocumentEvent */ public void insertUpdate(DocumentEvent e) { - final Integer pos = new Integer (e.getOffset()); + final Integer pos = e.getOffset(); if (SwingUtilities.isEventDispatchThread()) { firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); } else { @@ -2602,7 +2602,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @param e the DocumentEvent */ public void removeUpdate(DocumentEvent e) { - final Integer pos = new Integer (e.getOffset()); + final Integer pos = e.getOffset(); if (SwingUtilities.isEventDispatchThread()) { firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); } else { @@ -2624,7 +2624,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @param e the DocumentEvent */ public void changedUpdate(DocumentEvent e) { - final Integer pos = new Integer (e.getOffset()); + final Integer pos = e.getOffset(); if (SwingUtilities.isEventDispatchThread()) { firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); } else { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/NumberFormatter.java b/jdk/src/java.desktop/share/classes/javax/swing/text/NumberFormatter.java index 5b5cb3920df..b3db8fceb03 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/NumberFormatter.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/NumberFormatter.java @@ -73,7 +73,7 @@ import sun.swing.SwingUtilities2; * type the value class represents. For example: * setValueClass(Integer.class) will cause the resulting * value to be created via - * new Integer(((Number)formatter.parseObject(string)).intValue()). + * Integer.valueOf(((Number)formatter.parseObject(string)).intValue()). * This is typically useful if you * wish to set a min/max value as the various Number * implementations are generally not comparable to each other. This is also diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/StyleConstants.java b/jdk/src/java.desktop/share/classes/javax/swing/text/StyleConstants.java index 583b4dffd72..2aea5e5b2b5 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/StyleConstants.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/StyleConstants.java @@ -608,7 +608,7 @@ public class StyleConstants { * @param i the value */ public static void setFirstLineIndent(MutableAttributeSet a, float i) { - a.addAttribute(FirstLineIndent, new Float(i)); + a.addAttribute(FirstLineIndent, Float.valueOf(i)); } /** @@ -632,7 +632,7 @@ public class StyleConstants { * @param i the value */ public static void setRightIndent(MutableAttributeSet a, float i) { - a.addAttribute(RightIndent, new Float(i)); + a.addAttribute(RightIndent, Float.valueOf(i)); } /** @@ -656,7 +656,7 @@ public class StyleConstants { * @param i the value */ public static void setLeftIndent(MutableAttributeSet a, float i) { - a.addAttribute(LeftIndent, new Float(i)); + a.addAttribute(LeftIndent, Float.valueOf(i)); } /** @@ -680,7 +680,7 @@ public class StyleConstants { * @param i the value */ public static void setLineSpacing(MutableAttributeSet a, float i) { - a.addAttribute(LineSpacing, new Float(i)); + a.addAttribute(LineSpacing, Float.valueOf(i)); } /** @@ -704,7 +704,7 @@ public class StyleConstants { * @param i the value */ public static void setSpaceAbove(MutableAttributeSet a, float i) { - a.addAttribute(SpaceAbove, new Float(i)); + a.addAttribute(SpaceAbove, Float.valueOf(i)); } /** @@ -728,7 +728,7 @@ public class StyleConstants { * @param i the value */ public static void setSpaceBelow(MutableAttributeSet a, float i) { - a.addAttribute(SpaceBelow, new Float(i)); + a.addAttribute(SpaceBelow, Float.valueOf(i)); } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java b/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java index 06a8ebf6534..c6e715f6672 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java @@ -2564,7 +2564,7 @@ public class CSS implements Serializable { * represents the CSS attribute value */ Object toStyleConstants(StyleConstants key, View v) { - return new Float(getValue(false)); + return Float.valueOf(getValue(false)); } /** If true, span is a percentage value, and that to determine @@ -2837,25 +2837,25 @@ public class CSS implements Serializable { static Hashtable lengthMapping = new Hashtable(6); static Hashtable w3cLengthMapping = new Hashtable(6); static { - lengthMapping.put("pt", new Float(1f)); + lengthMapping.put("pt", Float.valueOf(1f)); // Not sure about 1.3, determined by experiementation. - lengthMapping.put("px", new Float(1.3f)); - lengthMapping.put("mm", new Float(2.83464f)); - lengthMapping.put("cm", new Float(28.3464f)); - lengthMapping.put("pc", new Float(12f)); - lengthMapping.put("in", new Float(72f)); + lengthMapping.put("px", Float.valueOf(1.3f)); + lengthMapping.put("mm", Float.valueOf(2.83464f)); + lengthMapping.put("cm", Float.valueOf(28.3464f)); + lengthMapping.put("pc", Float.valueOf(12f)); + lengthMapping.put("in", Float.valueOf(72f)); int res = 72; try { res = Toolkit.getDefaultToolkit().getScreenResolution(); } catch (HeadlessException e) { } // mapping according to the CSS2 spec - w3cLengthMapping.put("pt", new Float(res/72f)); - w3cLengthMapping.put("px", new Float(1f)); - w3cLengthMapping.put("mm", new Float(res/25.4f)); - w3cLengthMapping.put("cm", new Float(res/2.54f)); - w3cLengthMapping.put("pc", new Float(res/6f)); - w3cLengthMapping.put("in", new Float(res)); + w3cLengthMapping.put("pt", Float.valueOf(res/72f)); + w3cLengthMapping.put("px", Float.valueOf(1f)); + w3cLengthMapping.put("mm", Float.valueOf(res/25.4f)); + w3cLengthMapping.put("cm", Float.valueOf(res/2.54f)); + w3cLengthMapping.put("pc", Float.valueOf(res/6f)); + w3cLengthMapping.put("in", Float.valueOf((float)res)); } LengthUnit(String value, short defaultType, float defaultValue) { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/rtf/RTFAttributes.java b/jdk/src/java.desktop/share/classes/javax/swing/text/rtf/RTFAttributes.java index 99f2822cdcc..a58fb451de9 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/rtf/RTFAttributes.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/rtf/RTFAttributes.java @@ -357,7 +357,7 @@ class RTFAttributes public static NumericAttribute NewTwips(int d, Object s, String r, float ds, int dr) { - return new NumericAttribute(d, s, r, new Float(ds), dr, 20f); + return new NumericAttribute(d, s, r, Float.valueOf(ds), dr, 20f); } public static NumericAttribute NewTwips(int d, Object s, String r, @@ -378,7 +378,7 @@ class RTFAttributes if (scale == 1f) swingValue = Integer.valueOf(parameter); else - swingValue = new Float(parameter / scale); + swingValue = Float.valueOf(parameter / scale); target.addAttribute(swingName, swingValue); return true; } diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/PNGImageDecoder.java b/jdk/src/java.desktop/share/classes/sun/awt/image/PNGImageDecoder.java index 0627f91fca3..edc2fa2039f 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/PNGImageDecoder.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/PNGImageDecoder.java @@ -87,7 +87,7 @@ public class PNGImageDecoder extends ImageDecoder properties.put(key,value); } private void property(String key,float value) { - property(key,new Float(value)); + property(key, Float.valueOf(value)); } private final void pngassert(boolean b) throws IOException { if(!b) { diff --git a/jdk/src/java.desktop/share/classes/sun/print/ServiceDialog.java b/jdk/src/java.desktop/share/classes/sun/print/ServiceDialog.java index 615304c75f4..6e5a4cf3c93 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/ServiceDialog.java +++ b/jdk/src/java.desktop/share/classes/sun/print/ServiceDialog.java @@ -1402,8 +1402,8 @@ public class ServiceDialog extends JDialog implements ActionListener { format.setParseIntegerOnly(false); format.setDecimalSeparatorAlwaysShown(true); NumberFormatter nf = new NumberFormatter(format); - nf.setMinimum(new Float(0.0f)); - nf.setMaximum(new Float(999.0f)); + nf.setMinimum(Float.valueOf(0.0f)); + nf.setMaximum(Float.valueOf(999.0f)); nf.setAllowsInvalid(true); nf.setCommitsOnValidEdit(true); @@ -1836,10 +1836,10 @@ public class ServiceDialog extends JDialog implements ActionListener { rmVal = mediaSize.getX(units) - pax - paw; bmVal = mediaSize.getY(units) - pay - pah; - lmObj = new Float(lmVal); - rmObj = new Float(rmVal); - tmObj = new Float(tmVal); - bmObj = new Float(bmVal); + lmObj = lmVal; + rmObj = rmVal; + tmObj = tmVal; + bmObj = bmVal; /* Now we know the values to use, we need to assign them * to the fields appropriate for the orientation. diff --git a/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java b/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java index 4da098d504e..93f65327e08 100644 --- a/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java +++ b/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java @@ -117,7 +117,7 @@ public class PrintServiceLookupProvider extends PrintServiceLookup if (refreshTimeStr != null) { try { - minRefreshTime = (new Integer(refreshTimeStr)).intValue(); + minRefreshTime = (Integer.valueOf(refreshTimeStr)).intValue(); } catch (NumberFormatException e) { } if (minRefreshTime < DEFAULT_MINREFRESH) { From 20a9ca787508388551d9a4349e738ea0c5794c81 Mon Sep 17 00:00:00 2001 From: Alexander Kouznetsov Date: Mon, 25 Apr 2016 16:29:50 -0700 Subject: [PATCH 147/222] 8154594: JFrame.setDefaultCloseOperation is prohibited in jtreg: Missing part of the fix Reviewed-by: alexsch, prr --- .../src/com/sun/swingset3/demos/button/ButtonDemo.java | 5 +++-- .../com/sun/swingset3/demos/tabbedpane/TabbedPaneDemo.java | 1 - .../src/com/sun/swingset3/demos/window/WindowDemo.java | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java index e3aa888e5f3..358ae49d64b 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java @@ -36,6 +36,7 @@ import javax.swing.SwingUtilities; import com.sun.swingset3.DemoProperties; import com.sun.swingset3.demos.JHyperlink; +import java.lang.reflect.InvocationTargetException; /** * @@ -210,10 +211,10 @@ public final class ButtonDemo extends JPanel { return panel; } - public static void main(String args[]) { + public static void main(String args[]) throws InterruptedException, InvocationTargetException { final ButtonDemo buttonDemo = new ButtonDemo(); - javax.swing.SwingUtilities.invokeLater(() -> { + javax.swing.SwingUtilities.invokeAndWait(() -> { JFrame frame = new JFrame(DEMO_TITLE); frame.add(buttonDemo); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tabbedpane/TabbedPaneDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tabbedpane/TabbedPaneDemo.java index 9809d6babbe..5d023405b58 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tabbedpane/TabbedPaneDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tabbedpane/TabbedPaneDemo.java @@ -91,7 +91,6 @@ public class TabbedPaneDemo extends JPanel implements ActionListener { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new TabbedPaneDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java index 89b87776ba2..bbb06a1182a 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java @@ -31,6 +31,7 @@ import javax.swing.border.LineBorder; import com.sun.swingset3.DemoProperties; import com.sun.swingset3.demos.DemoUtilities; +import java.lang.reflect.InvocationTargetException; /** * @author aim @@ -145,8 +146,8 @@ public final class WindowDemo extends JPanel { } } - public static void main(String args[]) { - EventQueue.invokeLater(() -> { + public static void main(String args[]) throws InterruptedException, InvocationTargetException { + EventQueue.invokeAndWait(() -> { JFrame frame = new JFrame(); WindowDemo demo = new WindowDemo(); frame.add(demo); From 5125f7137636702fad6f2bef39c195e14aaeb83b Mon Sep 17 00:00:00 2001 From: Alexander Kouznetsov Date: Mon, 25 Apr 2016 16:34:03 -0700 Subject: [PATCH 148/222] 8154706: Sanity tests prepareBundle task doesn't produce working bundle Reviewed-by: alexsch, prr --- jdk/test/sanity/client/TEST.ROOT.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/sanity/client/TEST.ROOT.template b/jdk/test/sanity/client/TEST.ROOT.template index 6881809d9f8..e703c4ce236 100644 --- a/jdk/test/sanity/client/TEST.ROOT.template +++ b/jdk/test/sanity/client/TEST.ROOT.template @@ -12,7 +12,7 @@ # A "headful" test requires a graphical environment to meaningfully # run. Tests that are not headful are "headless." -keys=screenshots +keys=2d dnd i18n intermittent randomness headful # Tests that must run in othervm mode othervm.dirs=sanity/client/SwingSet From fb8f4acea810faab05065fcb045facf0b9a4bf35 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Tue, 26 Apr 2016 11:55:52 -0300 Subject: [PATCH 149/222] 8132994: /modules and /packages should not be parsed by the jimage parser Reviewed-by: sundar --- .../jlink/internal/ImageLocationWriter.java | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageLocationWriter.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageLocationWriter.java index e66ba64210b..0faf8c95d8b 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageLocationWriter.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageLocationWriter.java @@ -61,24 +61,32 @@ public final class ImageLocationWriter extends ImageLocation { String baseName; String extensionName = ""; - int offset = fullName.indexOf('/', 1); - if (fullName.length() >= 2 && fullName.charAt(0) == '/' && offset != -1) { - moduleName = fullName.substring(1, offset); - fullName = fullName.substring(offset + 1); - } - - offset = fullName.lastIndexOf('/'); - if (1 < offset) { - parentName = fullName.substring(0, offset); - fullName = fullName.substring(offset + 1); - } - - offset = fullName.lastIndexOf('.'); - if (offset != -1) { - baseName = fullName.substring(0, offset); - extensionName = fullName.substring(offset + 1); + if (fullName.startsWith("/modules/")) { + moduleName = "modules"; + baseName = fullName.substring("/modules/".length()); + } else if ( fullName.startsWith("/packages/")) { + moduleName = "packages"; + baseName = fullName.substring("/packages/".length()); } else { - baseName = fullName; + int offset = fullName.indexOf('/', 1); + if (fullName.length() >= 2 && fullName.charAt(0) == '/' && offset != -1) { + moduleName = fullName.substring(1, offset); + fullName = fullName.substring(offset + 1); + } + + offset = fullName.lastIndexOf('/'); + if (1 < offset) { + parentName = fullName.substring(0, offset); + fullName = fullName.substring(offset + 1); + } + + offset = fullName.lastIndexOf('.'); + if (offset != -1) { + baseName = fullName.substring(0, offset); + extensionName = fullName.substring(offset + 1); + } else { + baseName = fullName; + } } return new ImageLocationWriter(strings) From c08b6a7c8fcf4250eb5ec0ffb3b617b3faa955f6 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Tue, 26 Apr 2016 17:35:10 -0400 Subject: [PATCH 150/222] 8066750: Remove HTTP proxy implementation and tests from RMI Reviewed-by: smarks --- .../java/rmi/server/RMISocketFactory.java | 21 +- .../sun/rmi/transport/proxy/CGIHandler.java | 423 ---------------- .../proxy/HttpAwareServerSocket.java | 114 ----- .../rmi/transport/proxy/HttpInputStream.java | 205 -------- .../rmi/transport/proxy/HttpOutputStream.java | 80 --- .../transport/proxy/HttpReceiveSocket.java | 128 ----- .../transport/proxy/HttpSendInputStream.java | 161 ------ .../transport/proxy/HttpSendOutputStream.java | 105 ---- .../rmi/transport/proxy/HttpSendSocket.java | 344 ------------- .../proxy/RMIHttpToCGISocketFactory.java | 55 -- .../proxy/RMIHttpToPortSocketFactory.java | 53 -- .../proxy/RMIMasterSocketFactory.java | 468 ------------------ .../rmi/transport/proxy/RMISocketInfo.java | 39 -- .../rmi/transport/proxy/WrappedSocket.java | 192 ------- .../sun/rmi/transport/tcp/TCPConnection.java | 11 +- .../TCPDirectSocketFactory.java} | 4 +- .../sun/rmi/transport/tcp/TCPTransport.java | 30 +- jdk/test/ProblemList.txt | 2 - .../transport/httpSocket/HttpSocketTest.java | 113 ----- .../httpSocket/HttpSocketTest_Stub.java | 130 ----- .../rmi/transport/httpSocket/security.policy | 10 - .../proxy/DisableHttpDefaultValue.java | 69 --- .../transport/proxy/EagerHttpFallback.java | 73 --- .../tcp/blockAccept/BlockAcceptTest.java | 175 ------- .../transport/tcp/blockAccept/TestIface.java | 31 -- .../transport/tcp/blockAccept/TestImpl.java | 49 -- .../tcp/blockAccept/TestImpl_Stub.java | 66 --- .../transport/tcp/blockAccept/security.policy | 10 - 28 files changed, 10 insertions(+), 3151 deletions(-) delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java delete mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java rename jdk/src/java.rmi/share/classes/sun/rmi/transport/{proxy/RMIDirectSocketFactory.java => tcp/TCPDirectSocketFactory.java} (94%) delete mode 100644 jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java delete mode 100644 jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java delete mode 100644 jdk/test/java/rmi/transport/httpSocket/security.policy delete mode 100644 jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java delete mode 100644 jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java delete mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java delete mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java delete mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java delete mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java delete mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy diff --git a/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java b/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java index e69c269f81a..df3bc9fd24a 100644 --- a/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java +++ b/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,21 +35,8 @@ import java.net.*; * request that the RMI runtime use its socket factory instance * instead of the default implementation. * - *

    The default socket factory implementation performs a - * three-tiered approach to creating client sockets. First, a direct - * socket connection to the remote VM is attempted. If that fails - * (due to a firewall), the runtime uses HTTP with the explicit port - * number of the server. If the firewall does not allow this type of - * communication, then HTTP to a cgi-bin script on the server is used - * to POST the RMI call. The HTTP tunneling mechanisms are disabled by - * default. This behavior is controlled by the {@code java.rmi.server.disableHttp} - * property, whose default value is {@code true}. Setting this property's - * value to {@code false} will enable the HTTP tunneling mechanisms. - * - *

    Deprecated: HTTP Tunneling. The HTTP tunneling mechanisms - * described above, specifically HTTP with an explicit port and HTTP to a - * cgi-bin script, are deprecated. These HTTP tunneling mechanisms are - * subject to removal in a future release of the platform. + *

    The default socket factory implementation creates a direct + * socket connection to the remote host. * *

    The default socket factory implementation creates server sockets that * are bound to the wildcard address, which accepts requests from all network @@ -181,7 +168,7 @@ public abstract class RMISocketFactory public synchronized static RMISocketFactory getDefaultSocketFactory() { if (defaultSocketFactory == null) { defaultSocketFactory = - new sun.rmi.transport.proxy.RMIMasterSocketFactory(); + new sun.rmi.transport.tcp.TCPDirectSocketFactory(); } return defaultSocketFactory; } diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java deleted file mode 100644 index 546ccd8ea10..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; - -import java.io.*; -import java.net.*; -import java.util.Hashtable; - -/** - * CGIClientException is thrown when an error is detected - * in a client's request. - */ -class CGIClientException extends Exception { - private static final long serialVersionUID = 8147981687059865216L; - - public CGIClientException(String s) { - super(s); - } - - public CGIClientException(String s, Throwable cause) { - super(s, cause); - } -} - -/** - * CGIServerException is thrown when an error occurs here on the server. - */ -class CGIServerException extends Exception { - - private static final long serialVersionUID = 6928425456704527017L; - - public CGIServerException(String s) { - super(s); - } - - public CGIServerException(String s, Throwable cause) { - super(s, cause); - } -} - -/** - * CGICommandHandler is the interface to an object that handles a - * particular supported command. - */ -interface CGICommandHandler { - - /** - * Return the string form of the command - * to be recognized in the query string. - */ - public String getName(); - - /** - * Execute the command with the given string as parameter. - */ - public void execute(String param) throws CGIClientException, CGIServerException; -} - -/** - * The CGIHandler class contains methods for executing as a CGI program. - * The main function interprets the query string as a command of the form - * "{@code =}". - * - * This class depends on the CGI 1.0 environment variables being set as - * properties of the same name in this Java VM. - * - * All data and methods of this class are static because they are specific - * to this particular CGI process. - */ -public final class CGIHandler { - - /* get CGI parameters that we need */ - static int ContentLength; - static String QueryString; - static String RequestMethod; - static String ServerName; - static int ServerPort; - - static { - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Void run() { - ContentLength = - Integer.getInteger("CONTENT_LENGTH", 0).intValue(); - QueryString = System.getProperty("QUERY_STRING", ""); - RequestMethod = System.getProperty("REQUEST_METHOD", ""); - ServerName = System.getProperty("SERVER_NAME", ""); - ServerPort = Integer.getInteger("SERVER_PORT", 0).intValue(); - return null; - } - }); - } - - /* list of handlers for supported commands */ - private static CGICommandHandler commands[] = { - new CGIForwardCommand(), - new CGIGethostnameCommand(), - new CGIPingCommand(), - new CGITryHostnameCommand() - }; - - /* construct table mapping command strings to handlers */ - private static Hashtable commandLookup; - static { - commandLookup = new Hashtable<>(); - for (int i = 0; i < commands.length; ++ i) - commandLookup.put(commands[i].getName(), commands[i]); - } - - /* prevent instantiation of this class */ - private CGIHandler() {} - - /** - * Execute command given in query string on URL. The string before - * the first '=' is interpreted as the command name, and the string - * after the first '=' is the parameters to the command. - */ - public static void main(String args[]) - { - try { - String command, param; - int delim = QueryString.indexOf('='); - if (delim == -1) { - command = QueryString; - param = ""; - } - else { - command = QueryString.substring(0, delim); - param = QueryString.substring(delim + 1); - } - CGICommandHandler handler = - commandLookup.get(command); - if (handler != null) - try { - handler.execute(param); - } catch (CGIClientException e) { - e.printStackTrace(); - returnClientError(e.getMessage()); - } catch (CGIServerException e) { - e.printStackTrace(); - returnServerError(e.getMessage()); - } - else - returnClientError("invalid command."); - } catch (Exception e) { - e.printStackTrace(); - returnServerError("internal error: " + e.getMessage()); - } - System.exit(0); - } - - /** - * Return an HTML error message indicating there was error in - * the client's request. - */ - private static void returnClientError(String message) - { - System.out.println("Status: 400 Bad Request: " + message); - System.out.println("Content-type: text/html"); - System.out.println(""); - System.out.println("" + - "Java RMI Client Error" + - "" + - ""); - System.out.println("

    Java RMI Client Error

    "); - System.out.println(""); - System.out.println(message); - System.out.println(""); - System.exit(1); - } - - /** - * Return an HTML error message indicating an error occurred - * here on the server. - */ - private static void returnServerError(String message) - { - System.out.println("Status: 500 Server Error: " + message); - System.out.println("Content-type: text/html"); - System.out.println(""); - System.out.println("" + - "Java RMI Server Error" + - "" + - ""); - System.out.println("

    Java RMI Server Error

    "); - System.out.println(""); - System.out.println(message); - System.out.println(""); - System.exit(1); - } -} - -/** - * "forward" command: Forward request body to local port on the server, - * and send response back to client. - */ -final class CGIForwardCommand implements CGICommandHandler { - - public String getName() { - return "forward"; - } - - @SuppressWarnings("deprecation") - private String getLine (DataInputStream socketIn) throws IOException { - return socketIn.readLine(); - } - - public void execute(String param) throws CGIClientException, CGIServerException - { - if (!CGIHandler.RequestMethod.equals("POST")) - throw new CGIClientException("can only forward POST requests"); - - int port; - try { - port = Integer.parseInt(param); - } catch (NumberFormatException e) { - throw new CGIClientException("invalid port number.", e); - } - if (port <= 0 || port > 0xFFFF) - throw new CGIClientException("invalid port: " + port); - if (port < 1024) - throw new CGIClientException("permission denied for port: " + - port); - - byte buffer[]; - Socket socket; - try { - socket = new Socket(InetAddress.getLocalHost(), port); - } catch (IOException e) { - throw new CGIServerException("could not connect to local port", e); - } - - /* - * read client's request body - */ - DataInputStream clientIn = new DataInputStream(System.in); - buffer = new byte[CGIHandler.ContentLength]; - try { - clientIn.readFully(buffer); - } catch (EOFException e) { - throw new CGIClientException("unexpected EOF reading request body", e); - } catch (IOException e) { - throw new CGIClientException("error reading request body", e); - } - - /* - * send to local server in HTTP - */ - try { - DataOutputStream socketOut = - new DataOutputStream(socket.getOutputStream()); - socketOut.writeBytes("POST / HTTP/1.0\r\n"); - socketOut.writeBytes("Content-length: " + - CGIHandler.ContentLength + "\r\n\r\n"); - socketOut.write(buffer); - socketOut.flush(); - } catch (IOException e) { - throw new CGIServerException("error writing to server", e); - } - - /* - * read response - */ - DataInputStream socketIn; - try { - socketIn = new DataInputStream(socket.getInputStream()); - } catch (IOException e) { - throw new CGIServerException("error reading from server", e); - } - String key = "Content-length:".toLowerCase(); - boolean contentLengthFound = false; - String line; - int responseContentLength = -1; - do { - try { - line = getLine(socketIn); - } catch (IOException e) { - throw new CGIServerException("error reading from server", e); - } - if (line == null) - throw new CGIServerException( - "unexpected EOF reading server response"); - - if (line.toLowerCase().startsWith(key)) { - if (contentLengthFound) { - throw new CGIServerException( - "Multiple Content-length entries found."); - } else { - responseContentLength = - Integer.parseInt(line.substring(key.length()).trim()); - contentLengthFound = true; - } - } - } while ((line.length() != 0) && - (line.charAt(0) != '\r') && (line.charAt(0) != '\n')); - - if (!contentLengthFound || responseContentLength < 0) - throw new CGIServerException( - "missing or invalid content length in server response"); - buffer = new byte[responseContentLength]; - try { - socketIn.readFully(buffer); - } catch (EOFException e) { - throw new CGIServerException( - "unexpected EOF reading server response", e); - } catch (IOException e) { - throw new CGIServerException("error reading from server", e); - } - - /* - * send response back to client - */ - System.out.println("Status: 200 OK"); - System.out.println("Content-type: application/octet-stream"); - System.out.println(""); - try { - System.out.write(buffer); - } catch (IOException e) { - throw new CGIServerException("error writing response", e); - } - System.out.flush(); - } -} - -/** - * "gethostname" command: Return the host name of the server as the - * response body - */ -final class CGIGethostnameCommand implements CGICommandHandler { - - public String getName() { - return "gethostname"; - } - - public void execute(String param) - { - System.out.println("Status: 200 OK"); - System.out.println("Content-type: application/octet-stream"); - System.out.println("Content-length: " + - CGIHandler.ServerName.length()); - System.out.println(""); - System.out.print(CGIHandler.ServerName); - System.out.flush(); - } -} - -/** - * "ping" command: Return an OK status to indicate that connection - * was successful. - */ -final class CGIPingCommand implements CGICommandHandler { - - public String getName() { - return "ping"; - } - - public void execute(String param) - { - System.out.println("Status: 200 OK"); - System.out.println("Content-type: application/octet-stream"); - System.out.println("Content-length: 0"); - System.out.println(""); - } -} - -/** - * "tryhostname" command: Return a human readable message describing - * what host name is available to local Java VMs. - */ -final class CGITryHostnameCommand implements CGICommandHandler { - - public String getName() { - return "tryhostname"; - } - - public void execute(String param) - { - System.out.println("Status: 200 OK"); - System.out.println("Content-type: text/html"); - System.out.println(""); - System.out.println("" + - "Java RMI Server Hostname Info" + - "" + - ""); - System.out.println("

    Java RMI Server Hostname Info

    "); - System.out.println("

    Local host name available to Java VM:

    "); - System.out.print("

    InetAddress.getLocalHost().getHostName()"); - try { - String localHostName = InetAddress.getLocalHost().getHostName(); - - System.out.println(" = " + localHostName); - } catch (UnknownHostException e) { - System.out.println(" threw java.net.UnknownHostException"); - } - - System.out.println("

    Server host information obtained through CGI interface from HTTP server:

    "); - System.out.println("

    SERVER_NAME = " + CGIHandler.ServerName); - System.out.println("

    SERVER_PORT = " + CGIHandler.ServerPort); - System.out.println(""); - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java deleted file mode 100644 index b4512fecd93..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. - * 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 sun.rmi.transport.proxy; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; -import sun.rmi.runtime.Log; - -/** - * The HttpAwareServerSocket class extends the java.net.ServerSocket - * class. It behaves like a ServerSocket, except that if - * the first four bytes of an accepted socket are the letters "POST", - * then it returns an HttpReceiveSocket instead of a java.net.Socket. - * This means that the accept method blocks until four bytes have been - * read from the new socket's input stream. - */ -class HttpAwareServerSocket extends ServerSocket { - - /** - * Create a server socket on a specified port. - * @param port the port - * @exception IOException IO error when opening the socket. - */ - public HttpAwareServerSocket(int port) throws IOException - { - super(port); - } - - /** - * Create a server socket, bind it to the specified local port - * and listen to it. You can connect to an annonymous port by - * specifying the port number to be 0. backlog specifies - * how many connection requests the system will queue up while waiting - * for the ServerSocket to execute accept(). - * @param port the specified port - * @param backlog the number of queued connect requests pending accept - */ - public HttpAwareServerSocket(int port, int backlog) throws IOException - { - super(port, backlog); - } - - /** - * Accept a connection. This method will block until the connection - * is made and four bytes can be read from the input stream. - * If the first four bytes are "POST", then an HttpReceiveSocket is - * returned, which will handle the HTTP protocol wrapping. - * Otherwise, a WrappedSocket is returned. The input stream will be - * reset to the beginning of the transmission. - * In either case, a BufferedInputStream will already be on top of - * the underlying socket's input stream. - * @exception IOException IO error when waiting for the connection. - */ - public Socket accept() throws IOException - { - Socket socket = super.accept(); - BufferedInputStream in = - new BufferedInputStream(socket.getInputStream()); - - RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, - "socket accepted (checking for POST)"); - - in.mark(4); - boolean isHttp = (in.read() == 'P') && - (in.read() == 'O') && - (in.read() == 'S') && - (in.read() == 'T'); - in.reset(); - - if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.BRIEF)) { - RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, - (isHttp ? "POST found, HTTP socket returned" : - "POST not found, direct socket returned")); - } - - if (isHttp) - return new HttpReceiveSocket(socket, in, null); - else - return new WrappedSocket(socket, in, null); - } - - /** - * Return the implementation address and implementation port of - * the HttpAwareServerSocket as a String. - */ - public String toString() - { - return "HttpAware" + super.toString(); - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java deleted file mode 100644 index 4b5cad95044..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; - -import java.io.*; - -import sun.rmi.runtime.Log; - -/** - * The HttpInputStream class assists the HttpSendSocket and HttpReceiveSocket - * classes by filtering out the header for the message as well as any - * data after its proper content length. - */ -class HttpInputStream extends FilterInputStream { - - /** bytes remaining to be read from proper content of message */ - protected int bytesLeft; - - /** bytes remaining to be read at time of last mark */ - protected int bytesLeftAtMark; - - /** - * Create new filter on a given input stream. - * @param in the InputStream to filter from - */ - @SuppressWarnings("deprecation") - public HttpInputStream(InputStream in) throws IOException - { - super(in); - - if (in.markSupported()) - in.mark(0); // prevent resetting back to old marks - - // pull out header, looking for content length - - DataInputStream dis = new DataInputStream(in); - String key = "Content-length:".toLowerCase(); - boolean contentLengthFound = false; - String line; - do { - line = dis.readLine(); - - if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { - RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, - "received header line: \"" + line + "\""); - } - - if (line == null) - throw new EOFException(); - - if (line.toLowerCase().startsWith(key)) { - if (contentLengthFound) { - throw new IOException( - "Multiple Content-length entries found."); - } else { - bytesLeft = - Integer.parseInt(line.substring(key.length()).trim()); - contentLengthFound = true; - } - } - - // The idea here is to go past the first blank line. - // Some DataInputStream.readLine() documentation specifies that - // it does include the line-terminating character(s) in the - // returned string, but it actually doesn't, so we'll cover - // all cases here... - } while ((line.length() != 0) && - (line.charAt(0) != '\r') && (line.charAt(0) != '\n')); - - if (!contentLengthFound || bytesLeft < 0) { - // This really shouldn't happen, but if it does, shoud we fail?? - // For now, just give up and let a whole lot of bytes through... - bytesLeft = Integer.MAX_VALUE; - } - bytesLeftAtMark = bytesLeft; - - if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { - RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, - "content length: " + bytesLeft); - } - } - - /** - * Returns the number of bytes that can be read with blocking. - * Make sure that this does not exceed the number of bytes remaining - * in the proper content of the message. - */ - public int available() throws IOException - { - int bytesAvailable = in.available(); - if (bytesAvailable > bytesLeft) - bytesAvailable = bytesLeft; - - return bytesAvailable; - } - - /** - * Read a byte of data from the stream. Make sure that one is available - * from the proper content of the message, else -1 is returned to - * indicate to the user that the end of the stream has been reached. - */ - public int read() throws IOException - { - if (bytesLeft > 0) { - int data = in.read(); - if (data != -1) - -- bytesLeft; - - if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { - RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, - "received byte: '" + - ((data & 0x7F) < ' ' ? " " : String.valueOf((char) data)) + - "' " + data); - } - - return data; - } - else { - RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, - "read past content length"); - - return -1; - } - } - - public int read(byte b[], int off, int len) throws IOException - { - if (bytesLeft == 0 && len > 0) { - RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, - "read past content length"); - - return -1; - } - if (len > bytesLeft) - len = bytesLeft; - int bytesRead = in.read(b, off, len); - bytesLeft -= bytesRead; - - if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { - RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, - "read " + bytesRead + " bytes, " + bytesLeft + " remaining"); - } - - return bytesRead; - } - - /** - * Mark the current position in the stream (for future calls to reset). - * Remember where we are within the proper content of the message, so - * that a reset method call can recreate our state properly. - * @param readlimit how many bytes can be read before mark becomes invalid - */ - public void mark(int readlimit) - { - in.mark(readlimit); - if (in.markSupported()) - bytesLeftAtMark = bytesLeft; - } - - /** - * Repositions the stream to the last marked position. Make sure to - * adjust our position within the proper content accordingly. - */ - public void reset() throws IOException - { - in.reset(); - bytesLeft = bytesLeftAtMark; - } - - /** - * Skips bytes of the stream. Make sure to adjust our - * position within the proper content accordingly. - * @param n number of bytes to be skipped - */ - public long skip(long n) throws IOException - { - if (n > bytesLeft) - n = bytesLeft; - long bytesSkipped = in.skip(n); - bytesLeft -= bytesSkipped; - return bytesSkipped; - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java deleted file mode 100644 index 5f1f2a6a680..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. - * 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 sun.rmi.transport.proxy; - -import java.io.*; - -/** - * The HttpOutputStream class assists the HttpSendSocket and HttpReceiveSocket - * classes by providing an output stream that buffers its entire input until - * closed, and then it sends the complete transmission prefixed by the end of - * an HTTP header that specifies the content length. - */ -class HttpOutputStream extends ByteArrayOutputStream { - - /** the output stream to send response to */ - protected OutputStream out; - - /** true if HTTP response has been sent */ - boolean responseSent = false; - - /** - * Begin buffering new HTTP response to be sent to a given stream. - * @param out the OutputStream to send response to - */ - public HttpOutputStream(OutputStream out) { - super(); - this.out = out; - } - - /** - * On close, send HTTP-packaged response. - */ - public synchronized void close() throws IOException { - if (!responseSent) { - /* - * If response would have zero content length, then make it - * have some arbitrary data so that certain clients will not - * fail because the "document contains no data". - */ - if (size() == 0) - write(emptyData); - - DataOutputStream dos = new DataOutputStream(out); - dos.writeBytes("Content-type: application/octet-stream\r\n"); - dos.writeBytes("Content-length: " + size() + "\r\n"); - dos.writeBytes("\r\n"); - writeTo(dos); - dos.flush(); - // Do not close the underlying stream here, because that would - // close the underlying socket and prevent reading a response. - reset(); // reset byte array - responseSent = true; - } - } - - /** data to send if the response would otherwise be empty */ - private static byte[] emptyData = { 0 }; -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java deleted file mode 100644 index c916254ffcd..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved. - * 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 sun.rmi.transport.proxy; - -import java.io.*; -import java.net.Socket; -import java.net.InetAddress; - -/** - * The HttpReceiveSocket class extends the WrappedSocket class - * by removing the HTTP protocol packaging from the input stream and - * formatting the output stream as an HTTP response. - * - * NOTES: - * - * The output stream must be explicitly closed for the output to be - * sent, since the HttpResponseOutputStream needs to buffer the entire - * transmission to be able to fill in the content-length field of - * the HTTP header. Closing this socket will do this. - * - * The constructor blocks until the HTTP protocol header - * is received. This could be fixed, but I don't think it should be a - * problem because this object would not be created unless the - * HttpAwareServerSocket has detected the beginning of the header - * anyway, so the rest should be there. - * - * This socket can only be used to process one POST and reply to it. - * Another message would be received on a newly accepted socket anyway. - */ -public class HttpReceiveSocket extends WrappedSocket implements RMISocketInfo { - - /** true if the HTTP header has pushed through the output stream yet */ - private boolean headerSent = false; - - /** - * Layer on top of a pre-existing Socket object, and use specified - * input and output streams. - * @param socket the pre-existing socket to use - * @param in the InputStream to use for this socket (can be null) - * @param out the OutputStream to use for this socket (can be null) - */ - public HttpReceiveSocket(Socket socket, InputStream in, OutputStream out) - throws IOException - { - super(socket, in, out); - - this.in = new HttpInputStream(in != null ? in : - socket.getInputStream()); - this.out = (out != null ? out : - socket.getOutputStream()); - } - - /** - * Indicate that this socket is not reusable. - */ - public boolean isReusable() - { - return false; - } - - /** - * Get the address to which this socket is connected. "null" is always - * returned (to indicate an unknown address) because the originating - * host's IP address cannot be reliably determined: both because the - * request probably went through a proxy server, and because if it was - * delivered by a local forwarder (CGI script or servlet), we do NOT - * want it to appear as if the call is coming from the local host (in - * case the remote object makes access control decisions based on the - * "client host" of a remote call; see bugid 4399040). - */ - public InetAddress getInetAddress() { - return null; - } - - /** - * Get an OutputStream for this socket. - */ - public OutputStream getOutputStream() throws IOException - { - if (!headerSent) { // could this be done in constructor?? - DataOutputStream dos = new DataOutputStream(out); - dos.writeBytes("HTTP/1.0 200 OK\r\n"); - dos.flush(); - headerSent = true; - out = new HttpOutputStream(out); - } - return out; - } - - /** - * Close the socket. - */ - public synchronized void close() throws IOException - { - getOutputStream().close(); // make sure response is sent - socket.close(); - } - - /** - * Return string representation of the socket. - */ - public String toString() - { - return "HttpReceive" + socket.toString(); - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java deleted file mode 100644 index 0c6de28c266..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. - * 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 sun.rmi.transport.proxy; - -import java.io.*; - -/** - * The HttpSendInputStream class is used by the HttpSendSocket class as - * a layer on the top of the InputStream it returns so that it can be - * notified of attempts to read from it. This allows the HttpSendSocket - * to know when it should push across its output message. - */ -class HttpSendInputStream extends FilterInputStream { - - /** the HttpSendSocket object that is providing this stream */ - HttpSendSocket owner; - - /** - * Create new filter on a given input stream. - * @param in the InputStream to filter from - * @param owner the HttpSendSocket that is providing this stream - */ - public HttpSendInputStream(InputStream in, HttpSendSocket owner) - throws IOException - { - super(in); - - this.owner = owner; - } - - /** - * Mark this stream as inactive for its owner socket, so the next time - * a read is attempted, the owner will be notified and a new underlying - * input stream obtained. - */ - public void deactivate() - { - in = null; - } - - /** - * Read a byte of data from the stream. - */ - public int read() throws IOException - { - if (in == null) - in = owner.readNotify(); - return in.read(); - } - - /** - * Read into an array of bytes. - * @param b the buffer into which the data is to be read - * @param off the start offset of the data - * @param len the maximum number of bytes to read - */ - public int read(byte b[], int off, int len) throws IOException - { - if (len == 0) - return 0; - if (in == null) - in = owner.readNotify(); - return in.read(b, off, len); - } - - /** - * Skip bytes of input. - * @param n the number of bytes to be skipped - */ - public long skip(long n) throws IOException - { - if (n == 0) - return 0; - if (in == null) - in = owner.readNotify(); - return in.skip(n); - } - - /** - * Return the number of bytes that can be read without blocking. - */ - public int available() throws IOException - { - if (in == null) - in = owner.readNotify(); - return in.available(); - } - - /** - * Close the stream. - */ - public void close() throws IOException - { - owner.close(); - } - - /** - * Mark the current position in the stream. - * @param readlimit how many bytes can be read before mark becomes invalid - */ - public synchronized void mark(int readlimit) - { - if (in == null) { - try { - in = owner.readNotify(); - } - catch (IOException e) { - return; - } - } - in.mark(readlimit); - } - - /** - * Reposition the stream to the last marked position. - */ - public synchronized void reset() throws IOException - { - if (in == null) - in = owner.readNotify(); - in.reset(); - } - - /** - * Return true if this stream type supports mark/reset. - */ - public boolean markSupported() - { - if (in == null) { - try { - in = owner.readNotify(); - } - catch (IOException e) { - return false; - } - } - return in.markSupported(); - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java deleted file mode 100644 index bc83945534f..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. - * 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 sun.rmi.transport.proxy; - -import java.io.*; - -/** - * The HttpSendOutputStream class is used by the HttpSendSocket class as - * a layer on the top of the OutputStream it returns so that it can be - * notified of attempts to write to it. This allows the HttpSendSocket - * to know when it should construct a new message. - */ -class HttpSendOutputStream extends FilterOutputStream { - - /** the HttpSendSocket object that is providing this stream */ - HttpSendSocket owner; - - /** - * Create new filter on a given output stream. - * @param out the OutputStream to filter from - * @param owner the HttpSendSocket that is providing this stream - */ - public HttpSendOutputStream(OutputStream out, HttpSendSocket owner) - throws IOException - { - super(out); - - this.owner = owner; - } - - /** - * Mark this stream as inactive for its owner socket, so the next time - * a write is attempted, the owner will be notified and a new underlying - * output stream obtained. - */ - public void deactivate() - { - out = null; - } - - /** - * Write a byte of data to the stream. - */ - public void write(int b) throws IOException - { - if (out == null) - out = owner.writeNotify(); - out.write(b); - } - - /** - * Write a subarray of bytes. - * @param b the buffer from which the data is to be written - * @param off the start offset of the data - * @param len the number of bytes to be written - */ - public void write(byte b[], int off, int len) throws IOException - { - if (len == 0) - return; - if (out == null) - out = owner.writeNotify(); - out.write(b, off, len); - } - - /** - * Flush the stream. - */ - public void flush() throws IOException - { - if (out != null) - out.flush(); - } - - /** - * Close the stream. - */ - public void close() throws IOException - { - flush(); - owner.close(); - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java deleted file mode 100644 index a9932be35e1..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; - -import java.io.*; -import java.net.*; -import java.security.PrivilegedAction; - -import sun.rmi.runtime.Log; - -/** - * The HttpSendSocket class extends the java.net.Socket class - * by enclosing the data output stream in, then extracting the input - * stream from, an HTTP protocol transmission. - * - * NOTES: - * - * Since the length of the output request must be known before the - * HTTP header can be completed, all of the output is buffered by - * an HttpOutputStream object until either an attempt is made to - * read from this socket, or the socket is explicitly closed. - * - * On the first read attempt to read from this socket, the buffered - * output is sent to the destination as the body of an HTTP POST - * request. All reads will then acquire data from the body of - * the response. A subsequent attempt to write to this socket will - * throw an IOException. - */ -class HttpSendSocket extends Socket implements RMISocketInfo { - - /** the host to connect to */ - protected String host; - - /** the port to connect to */ - protected int port; - - /** the URL to forward through */ - protected URL url; - - /** the object managing this connection through the URL */ - protected URLConnection conn = null; - - /** internal input stream for this socket */ - protected InputStream in = null; - - /** internal output stream for this socket */ - protected OutputStream out = null; - - /** the notifying input stream returned to users */ - protected HttpSendInputStream inNotifier; - - /** the notifying output stream returned to users */ - protected HttpSendOutputStream outNotifier; - - /** - * Line separator string. This is the value of the line.separator - * property at the moment that the socket was created. - */ - private String lineSeparator = - java.security.AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("line.separator")); - - /** - * Create a stream socket and connect it to the specified port on - * the specified host. - * @param host the host - * @param port the port - */ - public HttpSendSocket(String host, int port, URL url) throws IOException - { - super((SocketImpl)null); // no underlying SocketImpl for this object - - if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { - RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, - "host = " + host + ", port = " + port + ", url = " + url); - } - - this.host = host; - this.port = port; - this.url = url; - - inNotifier = new HttpSendInputStream(null, this); - outNotifier = new HttpSendOutputStream(writeNotify(), this); - } - - /** - * Create a stream socket and connect it to the specified port on - * the specified host. - * @param host the host - * @param port the port - */ - public HttpSendSocket(String host, int port) throws IOException - { - this(host, port, new URL("http", host, port, "/")); - } - - /** - * Create a stream socket and connect it to the specified address on - * the specified port. - * @param address the address - * @param port the port - */ - public HttpSendSocket(InetAddress address, int port) throws IOException - { - this(address.getHostName(), port); - } - - /** - * Indicate that this socket is not reusable. - */ - public boolean isReusable() - { - return false; - } - - /** - * Create a new socket connection to host (or proxy), and prepare to - * send HTTP transmission. - */ - public synchronized OutputStream writeNotify() throws IOException - { - if (conn != null) { - throw new IOException("attempt to write on HttpSendSocket after " + - "request has been sent"); - } - - conn = url.openConnection(); - conn.setDoOutput(true); - conn.setUseCaches(false); - conn.setRequestProperty("Content-type", "application/octet-stream"); - - inNotifier.deactivate(); - in = null; - - return out = conn.getOutputStream(); - } - - /** - * Send HTTP output transmission and prepare to receive response. - */ - public synchronized InputStream readNotify() throws IOException - { - RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, - "sending request and activating input stream"); - - outNotifier.deactivate(); - out.close(); - out = null; - - try { - in = conn.getInputStream(); - } catch (IOException e) { - RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, - "failed to get input stream, exception: ", e); - - throw new IOException("HTTP request failed"); - } - - /* - * If an HTTP error response is returned, sometimes an IOException - * is thrown, which is handled above, and other times it isn't, and - * the error response body will be available for reading. - * As a safety net to catch any such unexpected HTTP behavior, we - * verify that the content type of the response is what the - * HttpOutputStream generates: "application/octet-stream". - * (Servers' error responses will generally be "text/html".) - * Any error response body is printed to the log. - */ - String contentType = conn.getContentType(); - if (contentType == null || - !conn.getContentType().equals("application/octet-stream")) - { - if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.BRIEF)) { - String message; - if (contentType == null) { - message = "missing content type in response" + - lineSeparator; - } else { - message = "invalid content type in response: " + - contentType + lineSeparator; - } - - message += "HttpSendSocket.readNotify: response body: "; - try { - BufferedReader din = new BufferedReader(new InputStreamReader(in)); - String line; - while ((line = din.readLine()) != null) - message += line + lineSeparator; - } catch (IOException e) { - } - RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, message); - } - - throw new IOException("HTTP request failed"); - } - - return in; - } - - /** - * Get the address to which the socket is connected. - */ - public InetAddress getInetAddress() - { - try { - return InetAddress.getByName(host); - } catch (UnknownHostException e) { - return null; // null if couldn't resolve destination host - } - } - - /** - * Get the local address to which the socket is bound. - */ - public InetAddress getLocalAddress() - { - try { - return InetAddress.getLocalHost(); - } catch (UnknownHostException e) { - return null; // null if couldn't determine local host - } - } - - /** - * Get the remote port to which the socket is connected. - */ - public int getPort() - { - return port; - } - - /** - * Get the local port to which the socket is connected. - */ - public int getLocalPort() - { - return -1; // request not applicable to this socket type - } - - /** - * Get an InputStream for this socket. - */ - public InputStream getInputStream() throws IOException - { - return inNotifier; - } - - /** - * Get an OutputStream for this socket. - */ - public OutputStream getOutputStream() throws IOException - { - return outNotifier; - } - - /** - * Enable/disable TCP_NODELAY. - * This operation has no effect for an HttpSendSocket. - */ - public void setTcpNoDelay(boolean on) throws SocketException - { - } - - /** - * Retrieve whether TCP_NODELAY is enabled. - */ - public boolean getTcpNoDelay() throws SocketException - { - return false; // imply option is disabled - } - - /** - * Enable/disable SO_LINGER with the specified linger time. - * This operation has no effect for an HttpSendSocket. - */ - public void setSoLinger(boolean on, int val) throws SocketException - { - } - - /** - * Retrive setting for SO_LINGER. - */ - public int getSoLinger() throws SocketException - { - return -1; // imply option is disabled - } - - /** - * Enable/disable SO_TIMEOUT with the specified timeout - * This operation has no effect for an HttpSendSocket. - */ - public synchronized void setSoTimeout(int timeout) throws SocketException - { - } - - /** - * Retrive setting for SO_TIMEOUT. - */ - public synchronized int getSoTimeout() throws SocketException - { - return 0; // imply option is disabled - } - - /** - * Close the socket. - */ - public synchronized void close() throws IOException - { - if (out != null) // push out transmission if not done - out.close(); - } - - /** - * Return string representation of this pseudo-socket. - */ - public String toString() - { - return "HttpSendSocket[host=" + host + - ",port=" + port + - ",url=" + url + "]"; - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java deleted file mode 100644 index 548f584ae11..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. - * 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 sun.rmi.transport.proxy; - -import java.io.IOException; -import java.net.Socket; -import java.net.ServerSocket; -import java.net.URL; -import java.rmi.server.RMISocketFactory; - -/** - * RMIHttpToCGISocketFactory creates a socket connection to the - * specified host that is comminicated within an HTTP request, - * forwarded through the default firewall proxy, to the target host's - * normal HTTP server, to a CGI program which forwards the request to - * the actual specified port on the socket. - */ -public class RMIHttpToCGISocketFactory extends RMISocketFactory { - - public Socket createSocket(String host, int port) - throws IOException - { - return new HttpSendSocket(host, port, - new URL("http", host, - "/cgi-bin/java-rmi.cgi" + - "?forward=" + port)); - } - - public ServerSocket createServerSocket(int port) throws IOException - { - return new HttpAwareServerSocket(port); - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java deleted file mode 100644 index c23df420e44..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. - * 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 sun.rmi.transport.proxy; - -import java.io.IOException; -import java.net.Socket; -import java.net.ServerSocket; -import java.net.URL; -import java.rmi.server.RMISocketFactory; - -/** - * RMIHttpToPortSocketFactory creates a socket connection to the - * specified host that is communicated within an HTTP request, - * forwarded through the default firewall proxy, directly to the - * specified port. - */ -public class RMIHttpToPortSocketFactory extends RMISocketFactory { - - public Socket createSocket(String host, int port) - throws IOException - { - return new HttpSendSocket(host, port, - new URL("http", host, port, "/")); - } - - public ServerSocket createServerSocket(int port) - throws IOException - { - return new HttpAwareServerSocket(port); - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java deleted file mode 100644 index 8cb7cc4185f..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; - -import java.io.*; -import java.net.*; -import java.security.*; -import java.util.*; -import java.rmi.server.LogStream; -import java.rmi.server.RMISocketFactory; -import sun.rmi.runtime.Log; -import sun.rmi.runtime.NewThreadAction; - -/** - * RMIMasterSocketFactory attempts to create a socket connection to the - * specified host using successively less efficient mechanisms - * until one succeeds. If the host is successfully connected to, - * the factory for the successful mechanism is stored in an internal - * hash table keyed by the host name, so that future attempts to - * connect to the same host will automatically use the same - * mechanism. - */ -@SuppressWarnings("deprecation") -public class RMIMasterSocketFactory extends RMISocketFactory { - - /** "proxy" package log level */ - static int logLevel = LogStream.parseLevel(getLogLevel()); - - private static String getLogLevel() { - return java.security.AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("sun.rmi.transport.proxy.logLevel")); - } - - /* proxy package log */ - static final Log proxyLog = - Log.getLog("sun.rmi.transport.tcp.proxy", - "transport", RMIMasterSocketFactory.logLevel); - - /** timeout for attemping direct socket connections */ - private static long connectTimeout = getConnectTimeout(); - - private static long getConnectTimeout() { - return java.security.AccessController.doPrivileged((PrivilegedAction) () -> - Long.getLong("sun.rmi.transport.proxy.connectTimeout", 15000)); // default: 15 seconds - } - - /** whether to fallback to HTTP on general connect failures */ - private static final boolean eagerHttpFallback = - java.security.AccessController.doPrivileged((PrivilegedAction) () -> - Boolean.getBoolean("sun.rmi.transport.proxy.eagerHttpFallback")); - - /** table of hosts successfully connected to and the factory used */ - private Hashtable successTable = - new Hashtable<>(); - - /** maximum number of hosts to remember successful connection to */ - private static final int MaxRememberedHosts = 64; - - /** list of the hosts in successTable in initial connection order */ - private Vector hostList = new Vector<>(MaxRememberedHosts); - - /** default factory for initial use for direct socket connection */ - protected RMISocketFactory initialFactory = new RMIDirectSocketFactory(); - - /** ordered list of factories to try as alternate connection - * mechanisms if a direct socket connections fails */ - protected Vector altFactoryList; - - /** - * Create a RMIMasterSocketFactory object. Establish order of - * connection mechanisms to attempt on createSocket, if a direct - * socket connection fails. - */ - public RMIMasterSocketFactory() { - altFactoryList = new Vector<>(2); - boolean setFactories = false; - - try { - String proxyHost; - proxyHost = java.security.AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("http.proxyHost")); - - if (proxyHost == null) - proxyHost = java.security.AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("proxyHost")); - - boolean disable = java.security.AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("java.rmi.server.disableHttp", "true")) - .equalsIgnoreCase("true"); - - if (!disable && proxyHost != null && proxyHost.length() > 0) { - setFactories = true; - } - } catch (Exception e) { - // unable to obtain the properties, so use the default behavior. - } - - if (setFactories) { - altFactoryList.addElement(new RMIHttpToPortSocketFactory()); - altFactoryList.addElement(new RMIHttpToCGISocketFactory()); - } - } - - /** - * Create a new client socket. If we remember connecting to this host - * successfully before, then use the same factory again. Otherwise, - * try using a direct socket connection and then the alternate factories - * in the order specified in altFactoryList. - */ - public Socket createSocket(String host, int port) - throws IOException - { - if (proxyLog.isLoggable(Log.BRIEF)) { - proxyLog.log(Log.BRIEF, "host: " + host + ", port: " + port); - } - - /* - * If we don't have any alternate factories to consult, short circuit - * the fallback procedure and delegate to the initial factory. - */ - if (altFactoryList.size() == 0) { - return initialFactory.createSocket(host, port); - } - - RMISocketFactory factory; - - /* - * If we remember successfully connecting to this host before, - * use the same factory. - */ - factory = successTable.get(host); - if (factory != null) { - if (proxyLog.isLoggable(Log.BRIEF)) { - proxyLog.log(Log.BRIEF, - "previously successful factory found: " + factory); - } - return factory.createSocket(host, port); - } - - /* - * Next, try a direct socket connection. Open socket in another - * thread and only wait for specified timeout, in case the socket - * would otherwise spend minutes trying an unreachable host. - */ - Socket initialSocket = null; - Socket fallbackSocket = null; - final AsyncConnector connector = - new AsyncConnector(initialFactory, host, port, - AccessController.getContext()); - // connection must be attempted with - // this thread's access control context - IOException initialFailure = null; - - try { - synchronized (connector) { - - Thread t = java.security.AccessController.doPrivileged( - new NewThreadAction(connector, "AsyncConnector", true)); - t.start(); - - try { - long now = System.currentTimeMillis(); - long deadline = now + connectTimeout; - do { - connector.wait(deadline - now); - initialSocket = checkConnector(connector); - if (initialSocket != null) - break; - now = System.currentTimeMillis(); - } while (now < deadline); - } catch (InterruptedException e) { - throw new InterruptedIOException( - "interrupted while waiting for connector"); - } - } - - // assume no route to host (for now) if no connection yet - if (initialSocket == null) - throw new NoRouteToHostException( - "connect timed out: " + host); - - proxyLog.log(Log.BRIEF, "direct socket connection successful"); - - return initialSocket; - - } catch (UnknownHostException | NoRouteToHostException e) { - initialFailure = e; - } catch (SocketException e) { - if (eagerHttpFallback) { - initialFailure = e; - } else { - throw e; - } - } finally { - if (initialFailure != null) { - - if (proxyLog.isLoggable(Log.BRIEF)) { - proxyLog.log(Log.BRIEF, - "direct socket connection failed: ", initialFailure); - } - - // Finally, try any alternate connection mechanisms. - for (int i = 0; i < altFactoryList.size(); ++ i) { - factory = altFactoryList.elementAt(i); - if (proxyLog.isLoggable(Log.BRIEF)) { - proxyLog.log(Log.BRIEF, - "trying with factory: " + factory); - } - try (Socket testSocket = - factory.createSocket(host, port)) { - // For HTTP connections, the output (POST request) must - // be sent before we verify a successful connection. - // So, sacrifice a socket for the sake of testing... - // The following sequence should verify a successful - // HTTP connection if no IOException is thrown. - InputStream in = testSocket.getInputStream(); - int b = in.read(); // probably -1 for EOF... - } catch (IOException ex) { - if (proxyLog.isLoggable(Log.BRIEF)) { - proxyLog.log(Log.BRIEF, "factory failed: ", ex); - } - - continue; - } - proxyLog.log(Log.BRIEF, "factory succeeded"); - - // factory succeeded, open new socket for caller's use - try { - fallbackSocket = factory.createSocket(host, port); - } catch (IOException ex) { // if it fails 2nd time, - } // just give up - break; - } - } - } - - synchronized (successTable) { - try { - // check once again to see if direct connection succeeded - synchronized (connector) { - initialSocket = checkConnector(connector); - } - if (initialSocket != null) { - // if we had made another one as well, clean it up... - if (fallbackSocket != null) - fallbackSocket.close(); - return initialSocket; - } - // if connector ever does get socket, it won't be used - connector.notUsed(); - } catch (UnknownHostException | NoRouteToHostException e) { - initialFailure = e; - } catch (SocketException e) { - if (eagerHttpFallback) { - initialFailure = e; - } else { - throw e; - } - } - // if we had found an alternate mechanism, go and use it - if (fallbackSocket != null) { - // remember this successful host/factory pair - rememberFactory(host, factory); - return fallbackSocket; - } - throw initialFailure; - } - } - - /** - * Remember a successful factory for connecting to host. - * Currently, excess hosts are removed from the remembered list - * using a Least Recently Created strategy. - */ - void rememberFactory(String host, RMISocketFactory factory) { - synchronized (successTable) { - while (hostList.size() >= MaxRememberedHosts) { - successTable.remove(hostList.elementAt(0)); - hostList.removeElementAt(0); - } - hostList.addElement(host); - successTable.put(host, factory); - } - } - - /** - * Check if an AsyncConnector succeeded. If not, return socket - * given to fall back to. - */ - Socket checkConnector(AsyncConnector connector) - throws IOException - { - Exception e = connector.getException(); - if (e != null) { - e.fillInStackTrace(); - /* - * The AsyncConnector implementation guaranteed that the exception - * will be either an IOException or a RuntimeException, and we can - * only throw one of those, so convince that compiler that it must - * be one of those. - */ - if (e instanceof IOException) { - throw (IOException) e; - } else if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } else { - throw new Error("internal error: " + - "unexpected checked exception: " + e.toString()); - } - } - return connector.getSocket(); - } - - /** - * Create a new server socket. - */ - public ServerSocket createServerSocket(int port) throws IOException { - //return new HttpAwareServerSocket(port); - return initialFactory.createServerSocket(port); - } - - - /** - * AsyncConnector is used by RMIMasterSocketFactory to attempt socket - * connections on a separate thread. This allows RMIMasterSocketFactory - * to control how long it will wait for the connection to succeed. - */ - private class AsyncConnector implements Runnable { - - /** what factory to use to attempt connection */ - private RMISocketFactory factory; - - /** the host to connect to */ - private String host; - - /** the port to connect to */ - private int port; - - /** access control context to attempt connection within */ - private AccessControlContext acc; - - /** exception that occurred during connection, if any */ - private Exception exception = null; - - /** the connected socket, if successful */ - private Socket socket = null; - - /** socket should be closed after created, if ever */ - private boolean cleanUp = false; - - /** - * Create a new asynchronous connector object. - */ - AsyncConnector(RMISocketFactory factory, String host, int port, - AccessControlContext acc) - { - this.factory = factory; - this.host = host; - this.port = port; - this.acc = acc; - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkConnect(host, port); - } - } - - /** - * Attempt socket connection in separate thread. If successful, - * notify master waiting, - */ - public void run() { - try { - /* - * Using the privileges of the thread that wants to make the - * connection is tempting, but it will fail with applets with - * the current applet security manager because the applet - * network connection policy is not captured in the permission - * framework of the access control context we have. - * - * java.security.AccessController.beginPrivileged(acc); - */ - try { - Socket temp = factory.createSocket(host, port); - synchronized (this) { - socket = temp; - notify(); - } - rememberFactory(host, factory); - synchronized (this) { - if (cleanUp) - try { - socket.close(); - } catch (IOException e) { - } - } - } catch (Exception e) { - /* - * Note that the only exceptions which could actually have - * occurred here are IOException or RuntimeException. - */ - synchronized (this) { - exception = e; - notify(); - } - } - } finally { - /* - * See above comments for matching beginPrivileged() call that - * is also commented out. - * - * java.security.AccessController.endPrivileged(); - */ - } - } - - /** - * Get exception that occurred during connection attempt, if any. - * In the current implementation, this is guaranteed to be either - * an IOException or a RuntimeException. - */ - private synchronized Exception getException() { - return exception; - } - - /** - * Get successful socket, if any. - */ - private synchronized Socket getSocket() { - return socket; - } - - /** - * Note that this connector's socket, if ever successfully created, - * will not be used, so it should be cleaned up quickly - */ - synchronized void notUsed() { - if (socket != null) { - try { - socket.close(); - } catch (IOException e) { - } - } - cleanUp = true; - } - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java deleted file mode 100644 index 85008fb231e..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. - * 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 sun.rmi.transport.proxy; - -/** - * RMISocketInfo is an interface that extensions of the java.net.Socket - * class may use to provide more information on its capabilities. - */ -public interface RMISocketInfo { - - /** - * Return true if this socket can be used for more than one - * RMI call. If a socket does not implement this interface, then - * it is assumed to be reusable. - */ - public boolean isReusable(); -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java deleted file mode 100644 index 7bc8503f60f..00000000000 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; - -import java.io.*; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; -import java.security.AccessController; -import java.security.PrivilegedAction; - -/** - * The WrappedSocket class provides a general wrapper for providing an - * extended implementation of java.net.Socket that can be attached to - * a pre-existing Socket object. WrappedSocket itself provides a - * constructor for specifying alternate input or output streams to be - * returned than those of the underlying Socket. - */ -class WrappedSocket extends Socket { - - /** the underlying concrete socket */ - protected Socket socket; - - /** the input stream to return for socket */ - protected InputStream in = null; - - /** the output stream to return for socket */ - protected OutputStream out = null; - - /** - * Layer on top of a pre-existing Socket object, and use specified - * input and output streams. This allows the creator of the - * underlying socket to peek at the beginning of the input with a - * BufferedInputStream and determine which kind of socket - * to create, without consuming the input. - * @param socket the pre-existing socket to use - * @param in the InputStream to return to users (can be null) - * @param out the OutputStream to return to users (can be null) - */ - public WrappedSocket(Socket socket, InputStream in, OutputStream out) - throws IOException - { - super((java.net.SocketImpl)null); // no underlying SocketImpl for this object - this.socket = socket; - this.in = in; - this.out = out; - } - - /** - * Get the address to which the socket is connected. - */ - public InetAddress getInetAddress() - { - return socket.getInetAddress(); - } - - /** - * Get the local address to which the socket is bound. - */ - public InetAddress getLocalAddress() { - return AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public InetAddress run() { - return socket.getLocalAddress(); - - } - }); - } - - /** - * Get the remote port to which the socket is connected. - */ - public int getPort() - { - return socket.getPort(); - } - - /** - * Get the local port to which the socket is connected. - */ - public int getLocalPort() - { - return socket.getLocalPort(); - } - - /** - * Get an InputStream for this socket. - */ - public InputStream getInputStream() throws IOException - { - if (in == null) - in = socket.getInputStream(); - return in; - } - - /** - * Get an OutputStream for this socket. - */ - public OutputStream getOutputStream() throws IOException - { - if (out == null) - out = socket.getOutputStream(); - return out; - } - - /** - * Enable/disable TCP_NODELAY. - */ - public void setTcpNoDelay(boolean on) throws SocketException - { - socket.setTcpNoDelay(on); - } - - /** - * Retrieve whether TCP_NODELAY is enabled. - */ - public boolean getTcpNoDelay() throws SocketException - { - return socket.getTcpNoDelay(); - } - - /** - * Enable/disable SO_LINGER with the specified linger time. - */ - public void setSoLinger(boolean on, int val) throws SocketException - { - socket.setSoLinger(on, val); - } - - /** - * Retrive setting for SO_LINGER. - */ - public int getSoLinger() throws SocketException - { - return socket.getSoLinger(); - } - - /** - * Enable/disable SO_TIMEOUT with the specified timeout - */ - public synchronized void setSoTimeout(int timeout) throws SocketException - { - socket.setSoTimeout(timeout); - } - - /** - * Retrive setting for SO_TIMEOUT. - */ - public synchronized int getSoTimeout() throws SocketException - { - return socket.getSoTimeout(); - } - - /** - * Close the socket. - */ - public synchronized void close() throws IOException - { - socket.close(); - } - - /** - * Return string representation of the socket. - */ - public String toString() - { - return "Wrapped" + socket.toString(); - } -} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java index 08eb50b29a7..8b5a610005b 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * 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,14 +26,10 @@ package sun.rmi.transport.tcp; import java.io.*; -import java.net.InetAddress; import java.net.Socket; -import java.net.SocketException; import java.rmi.*; -import java.rmi.server.RMISocketFactory; import sun.rmi.runtime.Log; import sun.rmi.transport.*; -import sun.rmi.transport.proxy.*; public class TCPConnection implements Connection { @@ -120,10 +116,7 @@ public class TCPConnection implements Connection { */ public boolean isReusable() { - if ((socket != null) && (socket instanceof RMISocketInfo)) - return ((RMISocketInfo) socket).isReusable(); - else - return true; + return true; } /** diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIDirectSocketFactory.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java similarity index 94% rename from jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIDirectSocketFactory.java rename to jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java index 953d47ca400..8274742ec1b 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIDirectSocketFactory.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package sun.rmi.transport.proxy; +package sun.rmi.transport.tcp; import java.io.IOException; import java.net.Socket; @@ -33,7 +33,7 @@ import java.rmi.server.RMISocketFactory; * RMIDirectSocketFactory creates a direct socket connection to the * specified port on the specified host. */ -public class RMIDirectSocketFactory extends RMISocketFactory { +public class TCPDirectSocketFactory extends RMISocketFactory { public Socket createSocket(String host, int port) throws IOException { diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java index 1caa362803a..764abefb551 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,6 @@ import sun.rmi.transport.StreamRemoteCall; import sun.rmi.transport.Target; import sun.rmi.transport.Transport; import sun.rmi.transport.TransportConstants; -import sun.rmi.transport.proxy.HttpReceiveSocket; /** * TCPTransport is the socket-based implementation of the RMI Transport @@ -711,35 +710,10 @@ public class TCPTransport extends Transport { ? sockIn : new BufferedInputStream(sockIn); - // Read magic (or HTTP wrapper) - bufIn.mark(4); + // Read magic DataInputStream in = new DataInputStream(bufIn); int magic = in.readInt(); - if (magic == POST) { - tcpLog.log(Log.BRIEF, "decoding HTTP-wrapped call"); - - // It's really a HTTP-wrapped request. Repackage - // the socket in a HttpReceiveSocket, reinitialize - // sockIn and in, and reread magic. - bufIn.reset(); // unread "POST" - - try { - socket = new HttpReceiveSocket(socket, bufIn, null); - remoteHost = "0.0.0.0"; - sockIn = socket.getInputStream(); - bufIn = new BufferedInputStream(sockIn); - in = new DataInputStream(bufIn); - magic = in.readInt(); - - } catch (IOException e) { - throw new RemoteException("Error HTTP-unwrapping call", - e); - } - } - // bufIn's mark will invalidate itself when it overflows - // so it doesn't have to be turned off - // read and verify transport header short version = in.readShort(); if (magic != TransportConstants.Magic || diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 696c9cd270f..684b0cab3ab 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -191,8 +191,6 @@ java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java 7146541 linux-al java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java 7191877 generic-all -sun/rmi/transport/proxy/EagerHttpFallback.java 7195095 generic-all - java/rmi/activation/Activatable/extLoadedImpl/ext.sh 8062724 generic-all sun/rmi/rmic/newrmic/equivalence/run.sh 8145980 generic-all diff --git a/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java b/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java deleted file mode 100644 index 8999c3d7310..00000000000 --- a/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - * - * @summary HttpSocket functionality test - * @author Dana Burns - * - * @library ../../testlibrary - * @modules java.rmi/sun.rmi.registry - * java.rmi/sun.rmi.server - * java.rmi/sun.rmi.transport - * java.rmi/sun.rmi.transport.proxy - * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary HttpSocketTest HttpSocketTest_Stub - * @run main/othervm/policy=security.policy HttpSocketTest - */ - -/* - * This test assures remote methods can be carried out over RMI. - * After setting the RMI runtime socket factory to the http proxy version, - * a registry is created, a remote object (an instance of this class) is - * registered with it, and then it is exercised. - */ - -import java.rmi.Remote; -import java.rmi.RemoteException; -import java.rmi.Naming; -import java.rmi.RMISecurityManager; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.RMISocketFactory; -import java.rmi.server.UnicastRemoteObject; -import sun.rmi.transport.proxy.RMIHttpToPortSocketFactory; - -interface MyRemoteInterface extends Remote { - void setRemoteObject( Remote r ) throws RemoteException; - Remote getRemoteObject() throws RemoteException; -} - -public class HttpSocketTest extends UnicastRemoteObject - implements MyRemoteInterface -{ - private static final String NAME = "HttpSocketTest"; - - public HttpSocketTest() throws RemoteException{} - - private Remote ro; - - public static void main(String[] args) - throws Exception - { - - Registry registry = null; - - TestLibrary.suggestSecurityManager(null); - - // Set the socket factory. - System.err.println("installing socket factory"); - RMISocketFactory.setSocketFactory(new RMIHttpToPortSocketFactory()); - int registryPort = -1; - - try { - System.err.println("Starting registry"); - registry = TestLibrary.createRegistryOnUnusedPort(); - registryPort = TestLibrary.getRegistryPort(registry); - } catch (Exception e) { - TestLibrary.bomb(e); - } - - try { - registry.rebind( NAME, new HttpSocketTest() ); - MyRemoteInterface httpTest = - (MyRemoteInterface)Naming.lookup("//:" + registryPort + "/" + NAME); - httpTest.setRemoteObject( new HttpSocketTest() ); - Remote r = httpTest.getRemoteObject(); - - } catch (Exception e) { - TestLibrary.bomb(e); - } - - - } - - public void setRemoteObject( Remote ro ) throws RemoteException { - this.ro = ro; - } - - public Remote getRemoteObject() throws RemoteException { - return( this.ro ); - } - -} diff --git a/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java b/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java deleted file mode 100644 index 03757a3df20..00000000000 --- a/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. - * 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. - */ - -// Stub class generated by rmic, do not edit. -// Contents subject to change without notice. - -public final class HttpSocketTest_Stub - extends java.rmi.server.RemoteStub - implements MyRemoteInterface, java.rmi.Remote -{ - private static final java.rmi.server.Operation[] operations = { - new java.rmi.server.Operation("java.rmi.Remote getRemoteObject()"), - new java.rmi.server.Operation("void setRemoteObject(java.rmi.Remote)") - }; - - private static final long interfaceHash = 3775375480010579665L; - - private static final long serialVersionUID = 2; - - private static boolean useNewInvoke; - private static java.lang.reflect.Method $method_getRemoteObject_0; - private static java.lang.reflect.Method $method_setRemoteObject_1; - - static { - try { - java.rmi.server.RemoteRef.class.getMethod("invoke", - new java.lang.Class[] { - java.rmi.Remote.class, - java.lang.reflect.Method.class, - java.lang.Object[].class, - long.class - }); - useNewInvoke = true; - $method_getRemoteObject_0 = MyRemoteInterface.class.getMethod("getRemoteObject", new java.lang.Class[] {}); - $method_setRemoteObject_1 = MyRemoteInterface.class.getMethod("setRemoteObject", new java.lang.Class[] {java.rmi.Remote.class}); - } catch (java.lang.NoSuchMethodException e) { - useNewInvoke = false; - } - } - - // constructors - public HttpSocketTest_Stub() { - super(); - } - public HttpSocketTest_Stub(java.rmi.server.RemoteRef ref) { - super(ref); - } - - // methods from remote interfaces - - // implementation of getRemoteObject() - public java.rmi.Remote getRemoteObject() - throws java.rmi.RemoteException - { - try { - if (useNewInvoke) { - Object $result = ref.invoke(this, $method_getRemoteObject_0, null, -2578437860804964265L); - return ((java.rmi.Remote) $result); - } else { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash); - ref.invoke(call); - java.rmi.Remote $result; - try { - java.io.ObjectInput in = call.getInputStream(); - $result = (java.rmi.Remote) in.readObject(); - } catch (java.io.IOException e) { - throw new java.rmi.UnmarshalException("error unmarshalling return", e); - } catch (java.lang.ClassNotFoundException e) { - throw new java.rmi.UnmarshalException("error unmarshalling return", e); - } finally { - ref.done(call); - } - return $result; - } - } catch (java.lang.RuntimeException e) { - throw e; - } catch (java.rmi.RemoteException e) { - throw e; - } catch (java.lang.Exception e) { - throw new java.rmi.UnexpectedException("undeclared checked exception", e); - } - } - - // implementation of setRemoteObject(Remote) - public void setRemoteObject(java.rmi.Remote $param_Remote_1) - throws java.rmi.RemoteException - { - try { - if (useNewInvoke) { - ref.invoke(this, $method_setRemoteObject_1, new java.lang.Object[] {$param_Remote_1}, -7518632118115022871L); - } else { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash); - try { - java.io.ObjectOutput out = call.getOutputStream(); - out.writeObject($param_Remote_1); - } catch (java.io.IOException e) { - throw new java.rmi.MarshalException("error marshalling arguments", e); - } - ref.invoke(call); - ref.done(call); - } - } catch (java.lang.RuntimeException e) { - throw e; - } catch (java.rmi.RemoteException e) { - throw e; - } catch (java.lang.Exception e) { - throw new java.rmi.UnexpectedException("undeclared checked exception", e); - } - } -} diff --git a/jdk/test/java/rmi/transport/httpSocket/security.policy b/jdk/test/java/rmi/transport/httpSocket/security.policy deleted file mode 100644 index f1960c9772d..00000000000 --- a/jdk/test/java/rmi/transport/httpSocket/security.policy +++ /dev/null @@ -1,10 +0,0 @@ - -grant { - permission java.net.SocketPermission "*:1024-", "accept,connect,listen"; - permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry"; - permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server"; - permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport"; - permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.proxy"; - permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp"; - permission java.lang.RuntimePermission "setFactory"; -}; diff --git a/jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java b/jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java deleted file mode 100644 index 5449c3b8759..00000000000 --- a/jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - * @bug 8023862 - * @summary Verify that the default value of the java.rmi.server.disableHttp - * has been changed from false to true. - * @modules java.rmi/sun.rmi.transport.proxy - * @compile -XDignore.symbol.file DisableHttpDefaultValue.java - * - * @run main/othervm DisableHttpDefaultValue true - * @run main/othervm -Djava.rmi.server.disableHttp DisableHttpDefaultValue false - * @run main/othervm -Djava.rmi.server.disableHttp=false DisableHttpDefaultValue false - * @run main/othervm -Djava.rmi.server.disableHttp=xyzzy DisableHttpDefaultValue false - * @run main/othervm -Djava.rmi.server.disableHttp=true DisableHttpDefaultValue true - */ - -import sun.rmi.transport.proxy.RMIMasterSocketFactory; - -public class DisableHttpDefaultValue { - /** - * Subclass RMIMasterSocketFactory to get access to - * protected field altFactoryList. This list has a - * zero size if proxying is disabled. - */ - static class SocketFactory extends RMIMasterSocketFactory { - boolean proxyDisabled() { - return altFactoryList.size() == 0; - } - } - - /** - * Takes a single arg, which is the expected boolean value of - * java.rmi.server.disableHttp. - */ - public static void main(String[] args) throws Exception { - // Force there to be a proxy host, so that we are able to - // tell whether proxying is enabled or disabled. - System.setProperty("http.proxyHost", "proxy.example.com"); - - String propval = System.getProperty("java.rmi.server.disableHttp"); - String propdisp = (propval == null) ? "null" : ("\"" + propval + "\""); - boolean expected = Boolean.parseBoolean(args[0]); - boolean actual = new SocketFactory().proxyDisabled(); - System.out.printf("### prop=%s exp=%s act=%s%n", propdisp, expected, actual); - if (expected != actual) - throw new AssertionError(); - } -} diff --git a/jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java b/jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java deleted file mode 100644 index 5b5691701c7..00000000000 --- a/jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - * @bug 4290727 - * @summary Verify that ConnectException will trigger HTTP fallback if - * sun.rmi.transport.proxy.eagerHttpFallback system property is set. - * - * @library ../../../../java/rmi/testlibrary - * @modules java.rmi/sun.rmi.registry - * java.rmi/sun.rmi.server - * java.rmi/sun.rmi.transport - * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary - * @run main/othervm EagerHttpFallback - */ - -import java.rmi.*; -import java.rmi.registry.*; - -public class EagerHttpFallback { - - static final int INITIAL_PORT = TestLibrary.getUnusedRandomPort(); - static final int FALLBACK_PORT = TestLibrary.getUnusedRandomPort(); - - public static void main(String[] args) throws Exception { - System.setProperty("http.proxyHost", "127.0.0.1"); - System.setProperty("http.proxyPort", Integer.toString(FALLBACK_PORT)); - System.setProperty("sun.rmi.transport.proxy.eagerHttpFallback", - "true"); - LocateRegistry.createRegistry(FALLBACK_PORT); - - /* - * The call below should trigger a ConnectException in the - * RMIMasterSocketFactory when it attempts a direct connection to - * INITIAL_PORT, which no one is listening on. Since - * eagerHttpFallback is set, this ConnectException should trigger HTTP - * fallback, which will send a call through the HTTP proxy, which is - * configured to be localhost with a port behind which a registry is - * listening--so if fallback works properly, the list() call should - * succeed. - */ - try { - LocateRegistry.getRegistry(INITIAL_PORT).list(); - } catch (Exception e) { - System.err.println( - "call on registry stub with port " + INITIAL_PORT + - "did not successfully perform HTTP fallback to " + - FALLBACK_PORT); - throw e; - } - } -} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java b/jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java deleted file mode 100644 index 7de92ee2c47..00000000000 --- a/jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - * @bug 4203167 - * - * @summary RMI blocks in HttpAwareServerSocket.accept() if you telnet to it - * @author Adrian Colley - * - * @library ../../../../../java/rmi/testlibrary - * @modules java.rmi/sun.rmi.transport.proxy - * @build TestIface TestImpl TestImpl_Stub - * @run main/othervm/policy=security.policy/timeout=60 BlockAcceptTest - */ - -/* This test attempts to stymie the RMI accept loop. The accept loop in - * RMI endlessly accepts a connection, spawns a thread for it, and repeats. - * The accept() call can be replaced by a user-supplied library which - * might foolishly block indefinitely in its accept() method, which would - * prevent RMI from accepting other connections on that socket. - * - * Unfortunately, HttpAwareServerSocket (default server socket) is/was such - * a foolish thing. It reads 4 bytes to see if they're "POST" before - * returning. The bug fix is to move the HTTP stuff into the mainloop, - * which has the side effect of enabling it for non-default socketfactories. - * - * This test: - * 1. Creates an object and exports it. - * 2. Connects to the listening RMI port and sends nothing, to hold it up. - * 3. Makes a regular call, using HTTP tunnelling. - * 4. Fails to deadlock, thereby passing the test. - * - * Some runtime dependencies I'm trying to eliminate: - * 1. We don't know the port number until after exporting the object, but - * have to set it in http.proxyPort somehow. Hopefully http.proxyPort - * isn't read too soon or this test will fail with a ConnectException. - */ - -import java.rmi.*; -import java.rmi.server.RMISocketFactory; -import java.io.*; -import java.net.*; - -import sun.rmi.transport.proxy.RMIMasterSocketFactory; -import sun.rmi.transport.proxy.RMIHttpToPortSocketFactory; - -public class BlockAcceptTest -{ - public static void main(String[] args) - throws Exception - { - // Make trouble for ourselves - if (System.getSecurityManager() == null) - System.setSecurityManager(new RMISecurityManager()); - - // HTTP direct to the server port - System.setProperty("http.proxyHost", "127.0.0.1"); - - // Set the socket factory. - System.err.println("(installing HTTP-out socket factory)"); - HttpOutFactory fac = new HttpOutFactory(); - RMISocketFactory.setSocketFactory(fac); - - // Create remote object - TestImpl impl = new TestImpl(); - - // Export and get which port. - System.err.println("(exporting remote object)"); - TestIface stub = impl.export(); - try { - int port = fac.whichPort(); - - // Sanity - if (port == 0) - throw new Error("TEST FAILED: export didn't reserve a port(?)"); - - // Set the HTTP port, at last. - System.setProperty("http.proxyPort", port+""); - - // Now, connect to that port - //Thread.sleep(2000); - System.err.println("(connecting to listening port on 127.0.0.1:" + - port + ")"); - Socket DoS = new Socket("127.0.0.1", port); - // we hold the connection open until done with the test. - - // The test itself: make a remote call and see if it's blocked or - // if it works - //Thread.sleep(2000); - System.err.println("(making RMI-through-HTTP call)"); - System.err.println("(typical test failure deadlocks here)"); - String result = stub.testCall("dummy load"); - - System.err.println(" => " + result); - if (!("OK".equals(result))) - throw new Error("TEST FAILED: result not OK"); - System.err.println("Test passed."); - - // Clean up, including writing a byte to that connection just in - // case an optimizer thought of optimizing it out of existence - try { - DoS.getOutputStream().write(0); - DoS.getOutputStream().close(); - } catch (Throwable apathy) { - } - - } finally { - try { - impl.unexport(); - } catch (Throwable unmatter) { - } - } - - // Should exit here - } - - private static class HttpOutFactory - extends RMISocketFactory - { - private int servport = 0; - - public Socket createSocket(String h, int p) - throws IOException - { - return ((new RMIHttpToPortSocketFactory()).createSocket(h, p)); - } - - /** Create a server socket and remember which port it's on. - * Aborts if createServerSocket(0) is called twice, because then - * it doesn't know whether to remember the first or second port. - */ - public ServerSocket createServerSocket(int p) - throws IOException - { - ServerSocket ss; - ss = (new RMIMasterSocketFactory()).createServerSocket(p); - if (p == 0) { - if (servport != 0) { - System.err.println("TEST FAILED: " + - "Duplicate createServerSocket(0)"); - throw new Error("Test aborted (createServerSocket)"); - } - servport = ss.getLocalPort(); - } - return (ss); - } - - /** Return which port was reserved by createServerSocket(0). - * If the return value was 0, createServerSocket(0) wasn't called. - */ - public int whichPort() { - return (servport); - } - } // end class HttpOutFactory -} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java deleted file mode 100644 index 85bab51483d..00000000000 --- a/jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. - * 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.rmi.*; - -public interface TestIface - extends Remote -{ - public String testCall(String ign) - throws RemoteException; -} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java deleted file mode 100644 index 73601a9e3b6..00000000000 --- a/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. - * 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.rmi.*; -import java.rmi.server.*; - -public class TestImpl - extends Object - implements TestIface -{ - public TestImpl() { - } - - public TestIface export() - throws RemoteException - { - return (TestIface)UnicastRemoteObject.exportObject(this); - } - - public void unexport() - throws NoSuchObjectException - { - UnicastRemoteObject.unexportObject(this, true); - } - - public String testCall(String ign) { - return ("OK"); - } -} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java deleted file mode 100644 index 2de40012e16..00000000000 --- a/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. - * 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. - */ - -// Stub class generated by rmic, do not edit. -// Contents subject to change without notice. - -public final class TestImpl_Stub - extends java.rmi.server.RemoteStub - implements TestIface -{ - private static final long serialVersionUID = 2; - - private static java.lang.reflect.Method $method_testCall_0; - - static { - try { - $method_testCall_0 = TestIface.class.getMethod("testCall", new java.lang.Class[] {java.lang.String.class}); - } catch (java.lang.NoSuchMethodException e) { - throw new java.lang.NoSuchMethodError( - "stub class initialization failed"); - } - } - - // constructors - public TestImpl_Stub(java.rmi.server.RemoteRef ref) { - super(ref); - } - - // methods from remote interfaces - - // implementation of testCall(String) - public java.lang.String testCall(java.lang.String $param_String_1) - throws java.rmi.RemoteException - { - try { - Object $result = ref.invoke(this, $method_testCall_0, new java.lang.Object[] {$param_String_1}, -4495720265115653109L); - return ((java.lang.String) $result); - } catch (java.lang.RuntimeException e) { - throw e; - } catch (java.rmi.RemoteException e) { - throw e; - } catch (java.lang.Exception e) { - throw new java.rmi.UnexpectedException("undeclared checked exception", e); - } - } -} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy b/jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy deleted file mode 100644 index a8c8d0a64d8..00000000000 --- a/jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy +++ /dev/null @@ -1,10 +0,0 @@ -grant { - // Take this out once we can specify -Djava.security.debug on - // the run line and figure out what else is needed - permission java.security.AllPermission; - - permission java.net.SocketPermission "*:1024-65535", "connect,listen"; - permission java.util.PropertyPermission "http.proxyHost", "write"; - permission java.util.PropertyPermission "http.proxyPort", "write"; - permission java.lang.RuntimePermission "setFactory"; -}; From 727e63cad7366b75ebe71c7269f0c3515d066a9b Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Tue, 26 Apr 2016 21:25:18 -0400 Subject: [PATCH 151/222] 8155182: fix to JDK-8066750 broke jdk9 builds Restore RMI Http Proxy support for now Reviewed-by: darcy, lancea, smarks --- .../java/rmi/server/RMISocketFactory.java | 21 +- .../sun/rmi/transport/proxy/CGIHandler.java | 423 ++++++++++++++++ .../proxy/HttpAwareServerSocket.java | 114 +++++ .../rmi/transport/proxy/HttpInputStream.java | 205 ++++++++ .../rmi/transport/proxy/HttpOutputStream.java | 80 +++ .../transport/proxy/HttpReceiveSocket.java | 128 +++++ .../transport/proxy/HttpSendInputStream.java | 161 ++++++ .../transport/proxy/HttpSendOutputStream.java | 105 ++++ .../rmi/transport/proxy/HttpSendSocket.java | 344 +++++++++++++ .../RMIDirectSocketFactory.java} | 4 +- .../proxy/RMIHttpToCGISocketFactory.java | 55 ++ .../proxy/RMIHttpToPortSocketFactory.java | 53 ++ .../proxy/RMIMasterSocketFactory.java | 468 ++++++++++++++++++ .../rmi/transport/proxy/RMISocketInfo.java | 39 ++ .../rmi/transport/proxy/WrappedSocket.java | 192 +++++++ .../sun/rmi/transport/tcp/TCPConnection.java | 11 +- .../sun/rmi/transport/tcp/TCPTransport.java | 30 +- jdk/test/ProblemList.txt | 2 + .../transport/httpSocket/HttpSocketTest.java | 113 +++++ .../httpSocket/HttpSocketTest_Stub.java | 130 +++++ .../rmi/transport/httpSocket/security.policy | 10 + .../proxy/DisableHttpDefaultValue.java | 69 +++ .../transport/proxy/EagerHttpFallback.java | 73 +++ .../tcp/blockAccept/BlockAcceptTest.java | 175 +++++++ .../transport/tcp/blockAccept/TestIface.java | 31 ++ .../transport/tcp/blockAccept/TestImpl.java | 49 ++ .../tcp/blockAccept/TestImpl_Stub.java | 66 +++ .../transport/tcp/blockAccept/security.policy | 10 + 28 files changed, 3151 insertions(+), 10 deletions(-) create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java rename jdk/src/java.rmi/share/classes/sun/rmi/transport/{tcp/TCPDirectSocketFactory.java => proxy/RMIDirectSocketFactory.java} (94%) create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java create mode 100644 jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java create mode 100644 jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java create mode 100644 jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java create mode 100644 jdk/test/java/rmi/transport/httpSocket/security.policy create mode 100644 jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java create mode 100644 jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java create mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java create mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java create mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java create mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java create mode 100644 jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy diff --git a/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java b/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java index df3bc9fd24a..e69c269f81a 100644 --- a/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java +++ b/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,21 @@ import java.net.*; * request that the RMI runtime use its socket factory instance * instead of the default implementation. * - *

    The default socket factory implementation creates a direct - * socket connection to the remote host. + *

    The default socket factory implementation performs a + * three-tiered approach to creating client sockets. First, a direct + * socket connection to the remote VM is attempted. If that fails + * (due to a firewall), the runtime uses HTTP with the explicit port + * number of the server. If the firewall does not allow this type of + * communication, then HTTP to a cgi-bin script on the server is used + * to POST the RMI call. The HTTP tunneling mechanisms are disabled by + * default. This behavior is controlled by the {@code java.rmi.server.disableHttp} + * property, whose default value is {@code true}. Setting this property's + * value to {@code false} will enable the HTTP tunneling mechanisms. + * + *

    Deprecated: HTTP Tunneling. The HTTP tunneling mechanisms + * described above, specifically HTTP with an explicit port and HTTP to a + * cgi-bin script, are deprecated. These HTTP tunneling mechanisms are + * subject to removal in a future release of the platform. * *

    The default socket factory implementation creates server sockets that * are bound to the wildcard address, which accepts requests from all network @@ -168,7 +181,7 @@ public abstract class RMISocketFactory public synchronized static RMISocketFactory getDefaultSocketFactory() { if (defaultSocketFactory == null) { defaultSocketFactory = - new sun.rmi.transport.tcp.TCPDirectSocketFactory(); + new sun.rmi.transport.proxy.RMIMasterSocketFactory(); } return defaultSocketFactory; } diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java new file mode 100644 index 00000000000..546ccd8ea10 --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; + +import java.io.*; +import java.net.*; +import java.util.Hashtable; + +/** + * CGIClientException is thrown when an error is detected + * in a client's request. + */ +class CGIClientException extends Exception { + private static final long serialVersionUID = 8147981687059865216L; + + public CGIClientException(String s) { + super(s); + } + + public CGIClientException(String s, Throwable cause) { + super(s, cause); + } +} + +/** + * CGIServerException is thrown when an error occurs here on the server. + */ +class CGIServerException extends Exception { + + private static final long serialVersionUID = 6928425456704527017L; + + public CGIServerException(String s) { + super(s); + } + + public CGIServerException(String s, Throwable cause) { + super(s, cause); + } +} + +/** + * CGICommandHandler is the interface to an object that handles a + * particular supported command. + */ +interface CGICommandHandler { + + /** + * Return the string form of the command + * to be recognized in the query string. + */ + public String getName(); + + /** + * Execute the command with the given string as parameter. + */ + public void execute(String param) throws CGIClientException, CGIServerException; +} + +/** + * The CGIHandler class contains methods for executing as a CGI program. + * The main function interprets the query string as a command of the form + * "{@code =}". + * + * This class depends on the CGI 1.0 environment variables being set as + * properties of the same name in this Java VM. + * + * All data and methods of this class are static because they are specific + * to this particular CGI process. + */ +public final class CGIHandler { + + /* get CGI parameters that we need */ + static int ContentLength; + static String QueryString; + static String RequestMethod; + static String ServerName; + static int ServerPort; + + static { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + ContentLength = + Integer.getInteger("CONTENT_LENGTH", 0).intValue(); + QueryString = System.getProperty("QUERY_STRING", ""); + RequestMethod = System.getProperty("REQUEST_METHOD", ""); + ServerName = System.getProperty("SERVER_NAME", ""); + ServerPort = Integer.getInteger("SERVER_PORT", 0).intValue(); + return null; + } + }); + } + + /* list of handlers for supported commands */ + private static CGICommandHandler commands[] = { + new CGIForwardCommand(), + new CGIGethostnameCommand(), + new CGIPingCommand(), + new CGITryHostnameCommand() + }; + + /* construct table mapping command strings to handlers */ + private static Hashtable commandLookup; + static { + commandLookup = new Hashtable<>(); + for (int i = 0; i < commands.length; ++ i) + commandLookup.put(commands[i].getName(), commands[i]); + } + + /* prevent instantiation of this class */ + private CGIHandler() {} + + /** + * Execute command given in query string on URL. The string before + * the first '=' is interpreted as the command name, and the string + * after the first '=' is the parameters to the command. + */ + public static void main(String args[]) + { + try { + String command, param; + int delim = QueryString.indexOf('='); + if (delim == -1) { + command = QueryString; + param = ""; + } + else { + command = QueryString.substring(0, delim); + param = QueryString.substring(delim + 1); + } + CGICommandHandler handler = + commandLookup.get(command); + if (handler != null) + try { + handler.execute(param); + } catch (CGIClientException e) { + e.printStackTrace(); + returnClientError(e.getMessage()); + } catch (CGIServerException e) { + e.printStackTrace(); + returnServerError(e.getMessage()); + } + else + returnClientError("invalid command."); + } catch (Exception e) { + e.printStackTrace(); + returnServerError("internal error: " + e.getMessage()); + } + System.exit(0); + } + + /** + * Return an HTML error message indicating there was error in + * the client's request. + */ + private static void returnClientError(String message) + { + System.out.println("Status: 400 Bad Request: " + message); + System.out.println("Content-type: text/html"); + System.out.println(""); + System.out.println("" + + "Java RMI Client Error" + + "" + + ""); + System.out.println("

    Java RMI Client Error

    "); + System.out.println(""); + System.out.println(message); + System.out.println(""); + System.exit(1); + } + + /** + * Return an HTML error message indicating an error occurred + * here on the server. + */ + private static void returnServerError(String message) + { + System.out.println("Status: 500 Server Error: " + message); + System.out.println("Content-type: text/html"); + System.out.println(""); + System.out.println("" + + "Java RMI Server Error" + + "" + + ""); + System.out.println("

    Java RMI Server Error

    "); + System.out.println(""); + System.out.println(message); + System.out.println(""); + System.exit(1); + } +} + +/** + * "forward" command: Forward request body to local port on the server, + * and send response back to client. + */ +final class CGIForwardCommand implements CGICommandHandler { + + public String getName() { + return "forward"; + } + + @SuppressWarnings("deprecation") + private String getLine (DataInputStream socketIn) throws IOException { + return socketIn.readLine(); + } + + public void execute(String param) throws CGIClientException, CGIServerException + { + if (!CGIHandler.RequestMethod.equals("POST")) + throw new CGIClientException("can only forward POST requests"); + + int port; + try { + port = Integer.parseInt(param); + } catch (NumberFormatException e) { + throw new CGIClientException("invalid port number.", e); + } + if (port <= 0 || port > 0xFFFF) + throw new CGIClientException("invalid port: " + port); + if (port < 1024) + throw new CGIClientException("permission denied for port: " + + port); + + byte buffer[]; + Socket socket; + try { + socket = new Socket(InetAddress.getLocalHost(), port); + } catch (IOException e) { + throw new CGIServerException("could not connect to local port", e); + } + + /* + * read client's request body + */ + DataInputStream clientIn = new DataInputStream(System.in); + buffer = new byte[CGIHandler.ContentLength]; + try { + clientIn.readFully(buffer); + } catch (EOFException e) { + throw new CGIClientException("unexpected EOF reading request body", e); + } catch (IOException e) { + throw new CGIClientException("error reading request body", e); + } + + /* + * send to local server in HTTP + */ + try { + DataOutputStream socketOut = + new DataOutputStream(socket.getOutputStream()); + socketOut.writeBytes("POST / HTTP/1.0\r\n"); + socketOut.writeBytes("Content-length: " + + CGIHandler.ContentLength + "\r\n\r\n"); + socketOut.write(buffer); + socketOut.flush(); + } catch (IOException e) { + throw new CGIServerException("error writing to server", e); + } + + /* + * read response + */ + DataInputStream socketIn; + try { + socketIn = new DataInputStream(socket.getInputStream()); + } catch (IOException e) { + throw new CGIServerException("error reading from server", e); + } + String key = "Content-length:".toLowerCase(); + boolean contentLengthFound = false; + String line; + int responseContentLength = -1; + do { + try { + line = getLine(socketIn); + } catch (IOException e) { + throw new CGIServerException("error reading from server", e); + } + if (line == null) + throw new CGIServerException( + "unexpected EOF reading server response"); + + if (line.toLowerCase().startsWith(key)) { + if (contentLengthFound) { + throw new CGIServerException( + "Multiple Content-length entries found."); + } else { + responseContentLength = + Integer.parseInt(line.substring(key.length()).trim()); + contentLengthFound = true; + } + } + } while ((line.length() != 0) && + (line.charAt(0) != '\r') && (line.charAt(0) != '\n')); + + if (!contentLengthFound || responseContentLength < 0) + throw new CGIServerException( + "missing or invalid content length in server response"); + buffer = new byte[responseContentLength]; + try { + socketIn.readFully(buffer); + } catch (EOFException e) { + throw new CGIServerException( + "unexpected EOF reading server response", e); + } catch (IOException e) { + throw new CGIServerException("error reading from server", e); + } + + /* + * send response back to client + */ + System.out.println("Status: 200 OK"); + System.out.println("Content-type: application/octet-stream"); + System.out.println(""); + try { + System.out.write(buffer); + } catch (IOException e) { + throw new CGIServerException("error writing response", e); + } + System.out.flush(); + } +} + +/** + * "gethostname" command: Return the host name of the server as the + * response body + */ +final class CGIGethostnameCommand implements CGICommandHandler { + + public String getName() { + return "gethostname"; + } + + public void execute(String param) + { + System.out.println("Status: 200 OK"); + System.out.println("Content-type: application/octet-stream"); + System.out.println("Content-length: " + + CGIHandler.ServerName.length()); + System.out.println(""); + System.out.print(CGIHandler.ServerName); + System.out.flush(); + } +} + +/** + * "ping" command: Return an OK status to indicate that connection + * was successful. + */ +final class CGIPingCommand implements CGICommandHandler { + + public String getName() { + return "ping"; + } + + public void execute(String param) + { + System.out.println("Status: 200 OK"); + System.out.println("Content-type: application/octet-stream"); + System.out.println("Content-length: 0"); + System.out.println(""); + } +} + +/** + * "tryhostname" command: Return a human readable message describing + * what host name is available to local Java VMs. + */ +final class CGITryHostnameCommand implements CGICommandHandler { + + public String getName() { + return "tryhostname"; + } + + public void execute(String param) + { + System.out.println("Status: 200 OK"); + System.out.println("Content-type: text/html"); + System.out.println(""); + System.out.println("" + + "Java RMI Server Hostname Info" + + "" + + ""); + System.out.println("

    Java RMI Server Hostname Info

    "); + System.out.println("

    Local host name available to Java VM:

    "); + System.out.print("

    InetAddress.getLocalHost().getHostName()"); + try { + String localHostName = InetAddress.getLocalHost().getHostName(); + + System.out.println(" = " + localHostName); + } catch (UnknownHostException e) { + System.out.println(" threw java.net.UnknownHostException"); + } + + System.out.println("

    Server host information obtained through CGI interface from HTTP server:

    "); + System.out.println("

    SERVER_NAME = " + CGIHandler.ServerName); + System.out.println("

    SERVER_PORT = " + CGIHandler.ServerPort); + System.out.println(""); + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java new file mode 100644 index 00000000000..b4512fecd93 --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. + * 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 sun.rmi.transport.proxy; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import sun.rmi.runtime.Log; + +/** + * The HttpAwareServerSocket class extends the java.net.ServerSocket + * class. It behaves like a ServerSocket, except that if + * the first four bytes of an accepted socket are the letters "POST", + * then it returns an HttpReceiveSocket instead of a java.net.Socket. + * This means that the accept method blocks until four bytes have been + * read from the new socket's input stream. + */ +class HttpAwareServerSocket extends ServerSocket { + + /** + * Create a server socket on a specified port. + * @param port the port + * @exception IOException IO error when opening the socket. + */ + public HttpAwareServerSocket(int port) throws IOException + { + super(port); + } + + /** + * Create a server socket, bind it to the specified local port + * and listen to it. You can connect to an annonymous port by + * specifying the port number to be 0. backlog specifies + * how many connection requests the system will queue up while waiting + * for the ServerSocket to execute accept(). + * @param port the specified port + * @param backlog the number of queued connect requests pending accept + */ + public HttpAwareServerSocket(int port, int backlog) throws IOException + { + super(port, backlog); + } + + /** + * Accept a connection. This method will block until the connection + * is made and four bytes can be read from the input stream. + * If the first four bytes are "POST", then an HttpReceiveSocket is + * returned, which will handle the HTTP protocol wrapping. + * Otherwise, a WrappedSocket is returned. The input stream will be + * reset to the beginning of the transmission. + * In either case, a BufferedInputStream will already be on top of + * the underlying socket's input stream. + * @exception IOException IO error when waiting for the connection. + */ + public Socket accept() throws IOException + { + Socket socket = super.accept(); + BufferedInputStream in = + new BufferedInputStream(socket.getInputStream()); + + RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, + "socket accepted (checking for POST)"); + + in.mark(4); + boolean isHttp = (in.read() == 'P') && + (in.read() == 'O') && + (in.read() == 'S') && + (in.read() == 'T'); + in.reset(); + + if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.BRIEF)) { + RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, + (isHttp ? "POST found, HTTP socket returned" : + "POST not found, direct socket returned")); + } + + if (isHttp) + return new HttpReceiveSocket(socket, in, null); + else + return new WrappedSocket(socket, in, null); + } + + /** + * Return the implementation address and implementation port of + * the HttpAwareServerSocket as a String. + */ + public String toString() + { + return "HttpAware" + super.toString(); + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java new file mode 100644 index 00000000000..4b5cad95044 --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; + +import java.io.*; + +import sun.rmi.runtime.Log; + +/** + * The HttpInputStream class assists the HttpSendSocket and HttpReceiveSocket + * classes by filtering out the header for the message as well as any + * data after its proper content length. + */ +class HttpInputStream extends FilterInputStream { + + /** bytes remaining to be read from proper content of message */ + protected int bytesLeft; + + /** bytes remaining to be read at time of last mark */ + protected int bytesLeftAtMark; + + /** + * Create new filter on a given input stream. + * @param in the InputStream to filter from + */ + @SuppressWarnings("deprecation") + public HttpInputStream(InputStream in) throws IOException + { + super(in); + + if (in.markSupported()) + in.mark(0); // prevent resetting back to old marks + + // pull out header, looking for content length + + DataInputStream dis = new DataInputStream(in); + String key = "Content-length:".toLowerCase(); + boolean contentLengthFound = false; + String line; + do { + line = dis.readLine(); + + if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { + RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, + "received header line: \"" + line + "\""); + } + + if (line == null) + throw new EOFException(); + + if (line.toLowerCase().startsWith(key)) { + if (contentLengthFound) { + throw new IOException( + "Multiple Content-length entries found."); + } else { + bytesLeft = + Integer.parseInt(line.substring(key.length()).trim()); + contentLengthFound = true; + } + } + + // The idea here is to go past the first blank line. + // Some DataInputStream.readLine() documentation specifies that + // it does include the line-terminating character(s) in the + // returned string, but it actually doesn't, so we'll cover + // all cases here... + } while ((line.length() != 0) && + (line.charAt(0) != '\r') && (line.charAt(0) != '\n')); + + if (!contentLengthFound || bytesLeft < 0) { + // This really shouldn't happen, but if it does, shoud we fail?? + // For now, just give up and let a whole lot of bytes through... + bytesLeft = Integer.MAX_VALUE; + } + bytesLeftAtMark = bytesLeft; + + if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { + RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, + "content length: " + bytesLeft); + } + } + + /** + * Returns the number of bytes that can be read with blocking. + * Make sure that this does not exceed the number of bytes remaining + * in the proper content of the message. + */ + public int available() throws IOException + { + int bytesAvailable = in.available(); + if (bytesAvailable > bytesLeft) + bytesAvailable = bytesLeft; + + return bytesAvailable; + } + + /** + * Read a byte of data from the stream. Make sure that one is available + * from the proper content of the message, else -1 is returned to + * indicate to the user that the end of the stream has been reached. + */ + public int read() throws IOException + { + if (bytesLeft > 0) { + int data = in.read(); + if (data != -1) + -- bytesLeft; + + if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { + RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, + "received byte: '" + + ((data & 0x7F) < ' ' ? " " : String.valueOf((char) data)) + + "' " + data); + } + + return data; + } + else { + RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, + "read past content length"); + + return -1; + } + } + + public int read(byte b[], int off, int len) throws IOException + { + if (bytesLeft == 0 && len > 0) { + RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, + "read past content length"); + + return -1; + } + if (len > bytesLeft) + len = bytesLeft; + int bytesRead = in.read(b, off, len); + bytesLeft -= bytesRead; + + if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { + RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, + "read " + bytesRead + " bytes, " + bytesLeft + " remaining"); + } + + return bytesRead; + } + + /** + * Mark the current position in the stream (for future calls to reset). + * Remember where we are within the proper content of the message, so + * that a reset method call can recreate our state properly. + * @param readlimit how many bytes can be read before mark becomes invalid + */ + public void mark(int readlimit) + { + in.mark(readlimit); + if (in.markSupported()) + bytesLeftAtMark = bytesLeft; + } + + /** + * Repositions the stream to the last marked position. Make sure to + * adjust our position within the proper content accordingly. + */ + public void reset() throws IOException + { + in.reset(); + bytesLeft = bytesLeftAtMark; + } + + /** + * Skips bytes of the stream. Make sure to adjust our + * position within the proper content accordingly. + * @param n number of bytes to be skipped + */ + public long skip(long n) throws IOException + { + if (n > bytesLeft) + n = bytesLeft; + long bytesSkipped = in.skip(n); + bytesLeft -= bytesSkipped; + return bytesSkipped; + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java new file mode 100644 index 00000000000..5f1f2a6a680 --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. + * 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 sun.rmi.transport.proxy; + +import java.io.*; + +/** + * The HttpOutputStream class assists the HttpSendSocket and HttpReceiveSocket + * classes by providing an output stream that buffers its entire input until + * closed, and then it sends the complete transmission prefixed by the end of + * an HTTP header that specifies the content length. + */ +class HttpOutputStream extends ByteArrayOutputStream { + + /** the output stream to send response to */ + protected OutputStream out; + + /** true if HTTP response has been sent */ + boolean responseSent = false; + + /** + * Begin buffering new HTTP response to be sent to a given stream. + * @param out the OutputStream to send response to + */ + public HttpOutputStream(OutputStream out) { + super(); + this.out = out; + } + + /** + * On close, send HTTP-packaged response. + */ + public synchronized void close() throws IOException { + if (!responseSent) { + /* + * If response would have zero content length, then make it + * have some arbitrary data so that certain clients will not + * fail because the "document contains no data". + */ + if (size() == 0) + write(emptyData); + + DataOutputStream dos = new DataOutputStream(out); + dos.writeBytes("Content-type: application/octet-stream\r\n"); + dos.writeBytes("Content-length: " + size() + "\r\n"); + dos.writeBytes("\r\n"); + writeTo(dos); + dos.flush(); + // Do not close the underlying stream here, because that would + // close the underlying socket and prevent reading a response. + reset(); // reset byte array + responseSent = true; + } + } + + /** data to send if the response would otherwise be empty */ + private static byte[] emptyData = { 0 }; +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java new file mode 100644 index 00000000000..c916254ffcd --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved. + * 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 sun.rmi.transport.proxy; + +import java.io.*; +import java.net.Socket; +import java.net.InetAddress; + +/** + * The HttpReceiveSocket class extends the WrappedSocket class + * by removing the HTTP protocol packaging from the input stream and + * formatting the output stream as an HTTP response. + * + * NOTES: + * + * The output stream must be explicitly closed for the output to be + * sent, since the HttpResponseOutputStream needs to buffer the entire + * transmission to be able to fill in the content-length field of + * the HTTP header. Closing this socket will do this. + * + * The constructor blocks until the HTTP protocol header + * is received. This could be fixed, but I don't think it should be a + * problem because this object would not be created unless the + * HttpAwareServerSocket has detected the beginning of the header + * anyway, so the rest should be there. + * + * This socket can only be used to process one POST and reply to it. + * Another message would be received on a newly accepted socket anyway. + */ +public class HttpReceiveSocket extends WrappedSocket implements RMISocketInfo { + + /** true if the HTTP header has pushed through the output stream yet */ + private boolean headerSent = false; + + /** + * Layer on top of a pre-existing Socket object, and use specified + * input and output streams. + * @param socket the pre-existing socket to use + * @param in the InputStream to use for this socket (can be null) + * @param out the OutputStream to use for this socket (can be null) + */ + public HttpReceiveSocket(Socket socket, InputStream in, OutputStream out) + throws IOException + { + super(socket, in, out); + + this.in = new HttpInputStream(in != null ? in : + socket.getInputStream()); + this.out = (out != null ? out : + socket.getOutputStream()); + } + + /** + * Indicate that this socket is not reusable. + */ + public boolean isReusable() + { + return false; + } + + /** + * Get the address to which this socket is connected. "null" is always + * returned (to indicate an unknown address) because the originating + * host's IP address cannot be reliably determined: both because the + * request probably went through a proxy server, and because if it was + * delivered by a local forwarder (CGI script or servlet), we do NOT + * want it to appear as if the call is coming from the local host (in + * case the remote object makes access control decisions based on the + * "client host" of a remote call; see bugid 4399040). + */ + public InetAddress getInetAddress() { + return null; + } + + /** + * Get an OutputStream for this socket. + */ + public OutputStream getOutputStream() throws IOException + { + if (!headerSent) { // could this be done in constructor?? + DataOutputStream dos = new DataOutputStream(out); + dos.writeBytes("HTTP/1.0 200 OK\r\n"); + dos.flush(); + headerSent = true; + out = new HttpOutputStream(out); + } + return out; + } + + /** + * Close the socket. + */ + public synchronized void close() throws IOException + { + getOutputStream().close(); // make sure response is sent + socket.close(); + } + + /** + * Return string representation of the socket. + */ + public String toString() + { + return "HttpReceive" + socket.toString(); + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java new file mode 100644 index 00000000000..0c6de28c266 --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. + * 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 sun.rmi.transport.proxy; + +import java.io.*; + +/** + * The HttpSendInputStream class is used by the HttpSendSocket class as + * a layer on the top of the InputStream it returns so that it can be + * notified of attempts to read from it. This allows the HttpSendSocket + * to know when it should push across its output message. + */ +class HttpSendInputStream extends FilterInputStream { + + /** the HttpSendSocket object that is providing this stream */ + HttpSendSocket owner; + + /** + * Create new filter on a given input stream. + * @param in the InputStream to filter from + * @param owner the HttpSendSocket that is providing this stream + */ + public HttpSendInputStream(InputStream in, HttpSendSocket owner) + throws IOException + { + super(in); + + this.owner = owner; + } + + /** + * Mark this stream as inactive for its owner socket, so the next time + * a read is attempted, the owner will be notified and a new underlying + * input stream obtained. + */ + public void deactivate() + { + in = null; + } + + /** + * Read a byte of data from the stream. + */ + public int read() throws IOException + { + if (in == null) + in = owner.readNotify(); + return in.read(); + } + + /** + * Read into an array of bytes. + * @param b the buffer into which the data is to be read + * @param off the start offset of the data + * @param len the maximum number of bytes to read + */ + public int read(byte b[], int off, int len) throws IOException + { + if (len == 0) + return 0; + if (in == null) + in = owner.readNotify(); + return in.read(b, off, len); + } + + /** + * Skip bytes of input. + * @param n the number of bytes to be skipped + */ + public long skip(long n) throws IOException + { + if (n == 0) + return 0; + if (in == null) + in = owner.readNotify(); + return in.skip(n); + } + + /** + * Return the number of bytes that can be read without blocking. + */ + public int available() throws IOException + { + if (in == null) + in = owner.readNotify(); + return in.available(); + } + + /** + * Close the stream. + */ + public void close() throws IOException + { + owner.close(); + } + + /** + * Mark the current position in the stream. + * @param readlimit how many bytes can be read before mark becomes invalid + */ + public synchronized void mark(int readlimit) + { + if (in == null) { + try { + in = owner.readNotify(); + } + catch (IOException e) { + return; + } + } + in.mark(readlimit); + } + + /** + * Reposition the stream to the last marked position. + */ + public synchronized void reset() throws IOException + { + if (in == null) + in = owner.readNotify(); + in.reset(); + } + + /** + * Return true if this stream type supports mark/reset. + */ + public boolean markSupported() + { + if (in == null) { + try { + in = owner.readNotify(); + } + catch (IOException e) { + return false; + } + } + return in.markSupported(); + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java new file mode 100644 index 00000000000..bc83945534f --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. + * 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 sun.rmi.transport.proxy; + +import java.io.*; + +/** + * The HttpSendOutputStream class is used by the HttpSendSocket class as + * a layer on the top of the OutputStream it returns so that it can be + * notified of attempts to write to it. This allows the HttpSendSocket + * to know when it should construct a new message. + */ +class HttpSendOutputStream extends FilterOutputStream { + + /** the HttpSendSocket object that is providing this stream */ + HttpSendSocket owner; + + /** + * Create new filter on a given output stream. + * @param out the OutputStream to filter from + * @param owner the HttpSendSocket that is providing this stream + */ + public HttpSendOutputStream(OutputStream out, HttpSendSocket owner) + throws IOException + { + super(out); + + this.owner = owner; + } + + /** + * Mark this stream as inactive for its owner socket, so the next time + * a write is attempted, the owner will be notified and a new underlying + * output stream obtained. + */ + public void deactivate() + { + out = null; + } + + /** + * Write a byte of data to the stream. + */ + public void write(int b) throws IOException + { + if (out == null) + out = owner.writeNotify(); + out.write(b); + } + + /** + * Write a subarray of bytes. + * @param b the buffer from which the data is to be written + * @param off the start offset of the data + * @param len the number of bytes to be written + */ + public void write(byte b[], int off, int len) throws IOException + { + if (len == 0) + return; + if (out == null) + out = owner.writeNotify(); + out.write(b, off, len); + } + + /** + * Flush the stream. + */ + public void flush() throws IOException + { + if (out != null) + out.flush(); + } + + /** + * Close the stream. + */ + public void close() throws IOException + { + flush(); + owner.close(); + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java new file mode 100644 index 00000000000..a9932be35e1 --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java @@ -0,0 +1,344 @@ +/* + * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; + +import java.io.*; +import java.net.*; +import java.security.PrivilegedAction; + +import sun.rmi.runtime.Log; + +/** + * The HttpSendSocket class extends the java.net.Socket class + * by enclosing the data output stream in, then extracting the input + * stream from, an HTTP protocol transmission. + * + * NOTES: + * + * Since the length of the output request must be known before the + * HTTP header can be completed, all of the output is buffered by + * an HttpOutputStream object until either an attempt is made to + * read from this socket, or the socket is explicitly closed. + * + * On the first read attempt to read from this socket, the buffered + * output is sent to the destination as the body of an HTTP POST + * request. All reads will then acquire data from the body of + * the response. A subsequent attempt to write to this socket will + * throw an IOException. + */ +class HttpSendSocket extends Socket implements RMISocketInfo { + + /** the host to connect to */ + protected String host; + + /** the port to connect to */ + protected int port; + + /** the URL to forward through */ + protected URL url; + + /** the object managing this connection through the URL */ + protected URLConnection conn = null; + + /** internal input stream for this socket */ + protected InputStream in = null; + + /** internal output stream for this socket */ + protected OutputStream out = null; + + /** the notifying input stream returned to users */ + protected HttpSendInputStream inNotifier; + + /** the notifying output stream returned to users */ + protected HttpSendOutputStream outNotifier; + + /** + * Line separator string. This is the value of the line.separator + * property at the moment that the socket was created. + */ + private String lineSeparator = + java.security.AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("line.separator")); + + /** + * Create a stream socket and connect it to the specified port on + * the specified host. + * @param host the host + * @param port the port + */ + public HttpSendSocket(String host, int port, URL url) throws IOException + { + super((SocketImpl)null); // no underlying SocketImpl for this object + + if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { + RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, + "host = " + host + ", port = " + port + ", url = " + url); + } + + this.host = host; + this.port = port; + this.url = url; + + inNotifier = new HttpSendInputStream(null, this); + outNotifier = new HttpSendOutputStream(writeNotify(), this); + } + + /** + * Create a stream socket and connect it to the specified port on + * the specified host. + * @param host the host + * @param port the port + */ + public HttpSendSocket(String host, int port) throws IOException + { + this(host, port, new URL("http", host, port, "/")); + } + + /** + * Create a stream socket and connect it to the specified address on + * the specified port. + * @param address the address + * @param port the port + */ + public HttpSendSocket(InetAddress address, int port) throws IOException + { + this(address.getHostName(), port); + } + + /** + * Indicate that this socket is not reusable. + */ + public boolean isReusable() + { + return false; + } + + /** + * Create a new socket connection to host (or proxy), and prepare to + * send HTTP transmission. + */ + public synchronized OutputStream writeNotify() throws IOException + { + if (conn != null) { + throw new IOException("attempt to write on HttpSendSocket after " + + "request has been sent"); + } + + conn = url.openConnection(); + conn.setDoOutput(true); + conn.setUseCaches(false); + conn.setRequestProperty("Content-type", "application/octet-stream"); + + inNotifier.deactivate(); + in = null; + + return out = conn.getOutputStream(); + } + + /** + * Send HTTP output transmission and prepare to receive response. + */ + public synchronized InputStream readNotify() throws IOException + { + RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, + "sending request and activating input stream"); + + outNotifier.deactivate(); + out.close(); + out = null; + + try { + in = conn.getInputStream(); + } catch (IOException e) { + RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, + "failed to get input stream, exception: ", e); + + throw new IOException("HTTP request failed"); + } + + /* + * If an HTTP error response is returned, sometimes an IOException + * is thrown, which is handled above, and other times it isn't, and + * the error response body will be available for reading. + * As a safety net to catch any such unexpected HTTP behavior, we + * verify that the content type of the response is what the + * HttpOutputStream generates: "application/octet-stream". + * (Servers' error responses will generally be "text/html".) + * Any error response body is printed to the log. + */ + String contentType = conn.getContentType(); + if (contentType == null || + !conn.getContentType().equals("application/octet-stream")) + { + if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.BRIEF)) { + String message; + if (contentType == null) { + message = "missing content type in response" + + lineSeparator; + } else { + message = "invalid content type in response: " + + contentType + lineSeparator; + } + + message += "HttpSendSocket.readNotify: response body: "; + try { + BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line; + while ((line = din.readLine()) != null) + message += line + lineSeparator; + } catch (IOException e) { + } + RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, message); + } + + throw new IOException("HTTP request failed"); + } + + return in; + } + + /** + * Get the address to which the socket is connected. + */ + public InetAddress getInetAddress() + { + try { + return InetAddress.getByName(host); + } catch (UnknownHostException e) { + return null; // null if couldn't resolve destination host + } + } + + /** + * Get the local address to which the socket is bound. + */ + public InetAddress getLocalAddress() + { + try { + return InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + return null; // null if couldn't determine local host + } + } + + /** + * Get the remote port to which the socket is connected. + */ + public int getPort() + { + return port; + } + + /** + * Get the local port to which the socket is connected. + */ + public int getLocalPort() + { + return -1; // request not applicable to this socket type + } + + /** + * Get an InputStream for this socket. + */ + public InputStream getInputStream() throws IOException + { + return inNotifier; + } + + /** + * Get an OutputStream for this socket. + */ + public OutputStream getOutputStream() throws IOException + { + return outNotifier; + } + + /** + * Enable/disable TCP_NODELAY. + * This operation has no effect for an HttpSendSocket. + */ + public void setTcpNoDelay(boolean on) throws SocketException + { + } + + /** + * Retrieve whether TCP_NODELAY is enabled. + */ + public boolean getTcpNoDelay() throws SocketException + { + return false; // imply option is disabled + } + + /** + * Enable/disable SO_LINGER with the specified linger time. + * This operation has no effect for an HttpSendSocket. + */ + public void setSoLinger(boolean on, int val) throws SocketException + { + } + + /** + * Retrive setting for SO_LINGER. + */ + public int getSoLinger() throws SocketException + { + return -1; // imply option is disabled + } + + /** + * Enable/disable SO_TIMEOUT with the specified timeout + * This operation has no effect for an HttpSendSocket. + */ + public synchronized void setSoTimeout(int timeout) throws SocketException + { + } + + /** + * Retrive setting for SO_TIMEOUT. + */ + public synchronized int getSoTimeout() throws SocketException + { + return 0; // imply option is disabled + } + + /** + * Close the socket. + */ + public synchronized void close() throws IOException + { + if (out != null) // push out transmission if not done + out.close(); + } + + /** + * Return string representation of this pseudo-socket. + */ + public String toString() + { + return "HttpSendSocket[host=" + host + + ",port=" + port + + ",url=" + url + "]"; + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIDirectSocketFactory.java similarity index 94% rename from jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java rename to jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIDirectSocketFactory.java index 8274742ec1b..953d47ca400 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIDirectSocketFactory.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package sun.rmi.transport.tcp; +package sun.rmi.transport.proxy; import java.io.IOException; import java.net.Socket; @@ -33,7 +33,7 @@ import java.rmi.server.RMISocketFactory; * RMIDirectSocketFactory creates a direct socket connection to the * specified port on the specified host. */ -public class TCPDirectSocketFactory extends RMISocketFactory { +public class RMIDirectSocketFactory extends RMISocketFactory { public Socket createSocket(String host, int port) throws IOException { diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java new file mode 100644 index 00000000000..548f584ae11 --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. + * 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 sun.rmi.transport.proxy; + +import java.io.IOException; +import java.net.Socket; +import java.net.ServerSocket; +import java.net.URL; +import java.rmi.server.RMISocketFactory; + +/** + * RMIHttpToCGISocketFactory creates a socket connection to the + * specified host that is comminicated within an HTTP request, + * forwarded through the default firewall proxy, to the target host's + * normal HTTP server, to a CGI program which forwards the request to + * the actual specified port on the socket. + */ +public class RMIHttpToCGISocketFactory extends RMISocketFactory { + + public Socket createSocket(String host, int port) + throws IOException + { + return new HttpSendSocket(host, port, + new URL("http", host, + "/cgi-bin/java-rmi.cgi" + + "?forward=" + port)); + } + + public ServerSocket createServerSocket(int port) throws IOException + { + return new HttpAwareServerSocket(port); + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java new file mode 100644 index 00000000000..c23df420e44 --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. + * 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 sun.rmi.transport.proxy; + +import java.io.IOException; +import java.net.Socket; +import java.net.ServerSocket; +import java.net.URL; +import java.rmi.server.RMISocketFactory; + +/** + * RMIHttpToPortSocketFactory creates a socket connection to the + * specified host that is communicated within an HTTP request, + * forwarded through the default firewall proxy, directly to the + * specified port. + */ +public class RMIHttpToPortSocketFactory extends RMISocketFactory { + + public Socket createSocket(String host, int port) + throws IOException + { + return new HttpSendSocket(host, port, + new URL("http", host, port, "/")); + } + + public ServerSocket createServerSocket(int port) + throws IOException + { + return new HttpAwareServerSocket(port); + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java new file mode 100644 index 00000000000..8cb7cc4185f --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java @@ -0,0 +1,468 @@ +/* + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; + +import java.io.*; +import java.net.*; +import java.security.*; +import java.util.*; +import java.rmi.server.LogStream; +import java.rmi.server.RMISocketFactory; +import sun.rmi.runtime.Log; +import sun.rmi.runtime.NewThreadAction; + +/** + * RMIMasterSocketFactory attempts to create a socket connection to the + * specified host using successively less efficient mechanisms + * until one succeeds. If the host is successfully connected to, + * the factory for the successful mechanism is stored in an internal + * hash table keyed by the host name, so that future attempts to + * connect to the same host will automatically use the same + * mechanism. + */ +@SuppressWarnings("deprecation") +public class RMIMasterSocketFactory extends RMISocketFactory { + + /** "proxy" package log level */ + static int logLevel = LogStream.parseLevel(getLogLevel()); + + private static String getLogLevel() { + return java.security.AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("sun.rmi.transport.proxy.logLevel")); + } + + /* proxy package log */ + static final Log proxyLog = + Log.getLog("sun.rmi.transport.tcp.proxy", + "transport", RMIMasterSocketFactory.logLevel); + + /** timeout for attemping direct socket connections */ + private static long connectTimeout = getConnectTimeout(); + + private static long getConnectTimeout() { + return java.security.AccessController.doPrivileged((PrivilegedAction) () -> + Long.getLong("sun.rmi.transport.proxy.connectTimeout", 15000)); // default: 15 seconds + } + + /** whether to fallback to HTTP on general connect failures */ + private static final boolean eagerHttpFallback = + java.security.AccessController.doPrivileged((PrivilegedAction) () -> + Boolean.getBoolean("sun.rmi.transport.proxy.eagerHttpFallback")); + + /** table of hosts successfully connected to and the factory used */ + private Hashtable successTable = + new Hashtable<>(); + + /** maximum number of hosts to remember successful connection to */ + private static final int MaxRememberedHosts = 64; + + /** list of the hosts in successTable in initial connection order */ + private Vector hostList = new Vector<>(MaxRememberedHosts); + + /** default factory for initial use for direct socket connection */ + protected RMISocketFactory initialFactory = new RMIDirectSocketFactory(); + + /** ordered list of factories to try as alternate connection + * mechanisms if a direct socket connections fails */ + protected Vector altFactoryList; + + /** + * Create a RMIMasterSocketFactory object. Establish order of + * connection mechanisms to attempt on createSocket, if a direct + * socket connection fails. + */ + public RMIMasterSocketFactory() { + altFactoryList = new Vector<>(2); + boolean setFactories = false; + + try { + String proxyHost; + proxyHost = java.security.AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("http.proxyHost")); + + if (proxyHost == null) + proxyHost = java.security.AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("proxyHost")); + + boolean disable = java.security.AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("java.rmi.server.disableHttp", "true")) + .equalsIgnoreCase("true"); + + if (!disable && proxyHost != null && proxyHost.length() > 0) { + setFactories = true; + } + } catch (Exception e) { + // unable to obtain the properties, so use the default behavior. + } + + if (setFactories) { + altFactoryList.addElement(new RMIHttpToPortSocketFactory()); + altFactoryList.addElement(new RMIHttpToCGISocketFactory()); + } + } + + /** + * Create a new client socket. If we remember connecting to this host + * successfully before, then use the same factory again. Otherwise, + * try using a direct socket connection and then the alternate factories + * in the order specified in altFactoryList. + */ + public Socket createSocket(String host, int port) + throws IOException + { + if (proxyLog.isLoggable(Log.BRIEF)) { + proxyLog.log(Log.BRIEF, "host: " + host + ", port: " + port); + } + + /* + * If we don't have any alternate factories to consult, short circuit + * the fallback procedure and delegate to the initial factory. + */ + if (altFactoryList.size() == 0) { + return initialFactory.createSocket(host, port); + } + + RMISocketFactory factory; + + /* + * If we remember successfully connecting to this host before, + * use the same factory. + */ + factory = successTable.get(host); + if (factory != null) { + if (proxyLog.isLoggable(Log.BRIEF)) { + proxyLog.log(Log.BRIEF, + "previously successful factory found: " + factory); + } + return factory.createSocket(host, port); + } + + /* + * Next, try a direct socket connection. Open socket in another + * thread and only wait for specified timeout, in case the socket + * would otherwise spend minutes trying an unreachable host. + */ + Socket initialSocket = null; + Socket fallbackSocket = null; + final AsyncConnector connector = + new AsyncConnector(initialFactory, host, port, + AccessController.getContext()); + // connection must be attempted with + // this thread's access control context + IOException initialFailure = null; + + try { + synchronized (connector) { + + Thread t = java.security.AccessController.doPrivileged( + new NewThreadAction(connector, "AsyncConnector", true)); + t.start(); + + try { + long now = System.currentTimeMillis(); + long deadline = now + connectTimeout; + do { + connector.wait(deadline - now); + initialSocket = checkConnector(connector); + if (initialSocket != null) + break; + now = System.currentTimeMillis(); + } while (now < deadline); + } catch (InterruptedException e) { + throw new InterruptedIOException( + "interrupted while waiting for connector"); + } + } + + // assume no route to host (for now) if no connection yet + if (initialSocket == null) + throw new NoRouteToHostException( + "connect timed out: " + host); + + proxyLog.log(Log.BRIEF, "direct socket connection successful"); + + return initialSocket; + + } catch (UnknownHostException | NoRouteToHostException e) { + initialFailure = e; + } catch (SocketException e) { + if (eagerHttpFallback) { + initialFailure = e; + } else { + throw e; + } + } finally { + if (initialFailure != null) { + + if (proxyLog.isLoggable(Log.BRIEF)) { + proxyLog.log(Log.BRIEF, + "direct socket connection failed: ", initialFailure); + } + + // Finally, try any alternate connection mechanisms. + for (int i = 0; i < altFactoryList.size(); ++ i) { + factory = altFactoryList.elementAt(i); + if (proxyLog.isLoggable(Log.BRIEF)) { + proxyLog.log(Log.BRIEF, + "trying with factory: " + factory); + } + try (Socket testSocket = + factory.createSocket(host, port)) { + // For HTTP connections, the output (POST request) must + // be sent before we verify a successful connection. + // So, sacrifice a socket for the sake of testing... + // The following sequence should verify a successful + // HTTP connection if no IOException is thrown. + InputStream in = testSocket.getInputStream(); + int b = in.read(); // probably -1 for EOF... + } catch (IOException ex) { + if (proxyLog.isLoggable(Log.BRIEF)) { + proxyLog.log(Log.BRIEF, "factory failed: ", ex); + } + + continue; + } + proxyLog.log(Log.BRIEF, "factory succeeded"); + + // factory succeeded, open new socket for caller's use + try { + fallbackSocket = factory.createSocket(host, port); + } catch (IOException ex) { // if it fails 2nd time, + } // just give up + break; + } + } + } + + synchronized (successTable) { + try { + // check once again to see if direct connection succeeded + synchronized (connector) { + initialSocket = checkConnector(connector); + } + if (initialSocket != null) { + // if we had made another one as well, clean it up... + if (fallbackSocket != null) + fallbackSocket.close(); + return initialSocket; + } + // if connector ever does get socket, it won't be used + connector.notUsed(); + } catch (UnknownHostException | NoRouteToHostException e) { + initialFailure = e; + } catch (SocketException e) { + if (eagerHttpFallback) { + initialFailure = e; + } else { + throw e; + } + } + // if we had found an alternate mechanism, go and use it + if (fallbackSocket != null) { + // remember this successful host/factory pair + rememberFactory(host, factory); + return fallbackSocket; + } + throw initialFailure; + } + } + + /** + * Remember a successful factory for connecting to host. + * Currently, excess hosts are removed from the remembered list + * using a Least Recently Created strategy. + */ + void rememberFactory(String host, RMISocketFactory factory) { + synchronized (successTable) { + while (hostList.size() >= MaxRememberedHosts) { + successTable.remove(hostList.elementAt(0)); + hostList.removeElementAt(0); + } + hostList.addElement(host); + successTable.put(host, factory); + } + } + + /** + * Check if an AsyncConnector succeeded. If not, return socket + * given to fall back to. + */ + Socket checkConnector(AsyncConnector connector) + throws IOException + { + Exception e = connector.getException(); + if (e != null) { + e.fillInStackTrace(); + /* + * The AsyncConnector implementation guaranteed that the exception + * will be either an IOException or a RuntimeException, and we can + * only throw one of those, so convince that compiler that it must + * be one of those. + */ + if (e instanceof IOException) { + throw (IOException) e; + } else if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else { + throw new Error("internal error: " + + "unexpected checked exception: " + e.toString()); + } + } + return connector.getSocket(); + } + + /** + * Create a new server socket. + */ + public ServerSocket createServerSocket(int port) throws IOException { + //return new HttpAwareServerSocket(port); + return initialFactory.createServerSocket(port); + } + + + /** + * AsyncConnector is used by RMIMasterSocketFactory to attempt socket + * connections on a separate thread. This allows RMIMasterSocketFactory + * to control how long it will wait for the connection to succeed. + */ + private class AsyncConnector implements Runnable { + + /** what factory to use to attempt connection */ + private RMISocketFactory factory; + + /** the host to connect to */ + private String host; + + /** the port to connect to */ + private int port; + + /** access control context to attempt connection within */ + private AccessControlContext acc; + + /** exception that occurred during connection, if any */ + private Exception exception = null; + + /** the connected socket, if successful */ + private Socket socket = null; + + /** socket should be closed after created, if ever */ + private boolean cleanUp = false; + + /** + * Create a new asynchronous connector object. + */ + AsyncConnector(RMISocketFactory factory, String host, int port, + AccessControlContext acc) + { + this.factory = factory; + this.host = host; + this.port = port; + this.acc = acc; + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkConnect(host, port); + } + } + + /** + * Attempt socket connection in separate thread. If successful, + * notify master waiting, + */ + public void run() { + try { + /* + * Using the privileges of the thread that wants to make the + * connection is tempting, but it will fail with applets with + * the current applet security manager because the applet + * network connection policy is not captured in the permission + * framework of the access control context we have. + * + * java.security.AccessController.beginPrivileged(acc); + */ + try { + Socket temp = factory.createSocket(host, port); + synchronized (this) { + socket = temp; + notify(); + } + rememberFactory(host, factory); + synchronized (this) { + if (cleanUp) + try { + socket.close(); + } catch (IOException e) { + } + } + } catch (Exception e) { + /* + * Note that the only exceptions which could actually have + * occurred here are IOException or RuntimeException. + */ + synchronized (this) { + exception = e; + notify(); + } + } + } finally { + /* + * See above comments for matching beginPrivileged() call that + * is also commented out. + * + * java.security.AccessController.endPrivileged(); + */ + } + } + + /** + * Get exception that occurred during connection attempt, if any. + * In the current implementation, this is guaranteed to be either + * an IOException or a RuntimeException. + */ + private synchronized Exception getException() { + return exception; + } + + /** + * Get successful socket, if any. + */ + private synchronized Socket getSocket() { + return socket; + } + + /** + * Note that this connector's socket, if ever successfully created, + * will not be used, so it should be cleaned up quickly + */ + synchronized void notUsed() { + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + } + } + cleanUp = true; + } + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java new file mode 100644 index 00000000000..85008fb231e --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. + * 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 sun.rmi.transport.proxy; + +/** + * RMISocketInfo is an interface that extensions of the java.net.Socket + * class may use to provide more information on its capabilities. + */ +public interface RMISocketInfo { + + /** + * Return true if this socket can be used for more than one + * RMI call. If a socket does not implement this interface, then + * it is assumed to be reusable. + */ + public boolean isReusable(); +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java new file mode 100644 index 00000000000..7bc8503f60f --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 sun.rmi.transport.proxy; + +import java.io.*; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * The WrappedSocket class provides a general wrapper for providing an + * extended implementation of java.net.Socket that can be attached to + * a pre-existing Socket object. WrappedSocket itself provides a + * constructor for specifying alternate input or output streams to be + * returned than those of the underlying Socket. + */ +class WrappedSocket extends Socket { + + /** the underlying concrete socket */ + protected Socket socket; + + /** the input stream to return for socket */ + protected InputStream in = null; + + /** the output stream to return for socket */ + protected OutputStream out = null; + + /** + * Layer on top of a pre-existing Socket object, and use specified + * input and output streams. This allows the creator of the + * underlying socket to peek at the beginning of the input with a + * BufferedInputStream and determine which kind of socket + * to create, without consuming the input. + * @param socket the pre-existing socket to use + * @param in the InputStream to return to users (can be null) + * @param out the OutputStream to return to users (can be null) + */ + public WrappedSocket(Socket socket, InputStream in, OutputStream out) + throws IOException + { + super((java.net.SocketImpl)null); // no underlying SocketImpl for this object + this.socket = socket; + this.in = in; + this.out = out; + } + + /** + * Get the address to which the socket is connected. + */ + public InetAddress getInetAddress() + { + return socket.getInetAddress(); + } + + /** + * Get the local address to which the socket is bound. + */ + public InetAddress getLocalAddress() { + return AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public InetAddress run() { + return socket.getLocalAddress(); + + } + }); + } + + /** + * Get the remote port to which the socket is connected. + */ + public int getPort() + { + return socket.getPort(); + } + + /** + * Get the local port to which the socket is connected. + */ + public int getLocalPort() + { + return socket.getLocalPort(); + } + + /** + * Get an InputStream for this socket. + */ + public InputStream getInputStream() throws IOException + { + if (in == null) + in = socket.getInputStream(); + return in; + } + + /** + * Get an OutputStream for this socket. + */ + public OutputStream getOutputStream() throws IOException + { + if (out == null) + out = socket.getOutputStream(); + return out; + } + + /** + * Enable/disable TCP_NODELAY. + */ + public void setTcpNoDelay(boolean on) throws SocketException + { + socket.setTcpNoDelay(on); + } + + /** + * Retrieve whether TCP_NODELAY is enabled. + */ + public boolean getTcpNoDelay() throws SocketException + { + return socket.getTcpNoDelay(); + } + + /** + * Enable/disable SO_LINGER with the specified linger time. + */ + public void setSoLinger(boolean on, int val) throws SocketException + { + socket.setSoLinger(on, val); + } + + /** + * Retrive setting for SO_LINGER. + */ + public int getSoLinger() throws SocketException + { + return socket.getSoLinger(); + } + + /** + * Enable/disable SO_TIMEOUT with the specified timeout + */ + public synchronized void setSoTimeout(int timeout) throws SocketException + { + socket.setSoTimeout(timeout); + } + + /** + * Retrive setting for SO_TIMEOUT. + */ + public synchronized int getSoTimeout() throws SocketException + { + return socket.getSoTimeout(); + } + + /** + * Close the socket. + */ + public synchronized void close() throws IOException + { + socket.close(); + } + + /** + * Return string representation of the socket. + */ + public String toString() + { + return "Wrapped" + socket.toString(); + } +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java index 8b5a610005b..08eb50b29a7 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -26,10 +26,14 @@ package sun.rmi.transport.tcp; import java.io.*; +import java.net.InetAddress; import java.net.Socket; +import java.net.SocketException; import java.rmi.*; +import java.rmi.server.RMISocketFactory; import sun.rmi.runtime.Log; import sun.rmi.transport.*; +import sun.rmi.transport.proxy.*; public class TCPConnection implements Connection { @@ -116,7 +120,10 @@ public class TCPConnection implements Connection { */ public boolean isReusable() { - return true; + if ((socket != null) && (socket instanceof RMISocketInfo)) + return ((RMISocketInfo) socket).isReusable(); + else + return true; } /** diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java index 764abefb551..1caa362803a 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,6 +75,7 @@ import sun.rmi.transport.StreamRemoteCall; import sun.rmi.transport.Target; import sun.rmi.transport.Transport; import sun.rmi.transport.TransportConstants; +import sun.rmi.transport.proxy.HttpReceiveSocket; /** * TCPTransport is the socket-based implementation of the RMI Transport @@ -710,10 +711,35 @@ public class TCPTransport extends Transport { ? sockIn : new BufferedInputStream(sockIn); - // Read magic + // Read magic (or HTTP wrapper) + bufIn.mark(4); DataInputStream in = new DataInputStream(bufIn); int magic = in.readInt(); + if (magic == POST) { + tcpLog.log(Log.BRIEF, "decoding HTTP-wrapped call"); + + // It's really a HTTP-wrapped request. Repackage + // the socket in a HttpReceiveSocket, reinitialize + // sockIn and in, and reread magic. + bufIn.reset(); // unread "POST" + + try { + socket = new HttpReceiveSocket(socket, bufIn, null); + remoteHost = "0.0.0.0"; + sockIn = socket.getInputStream(); + bufIn = new BufferedInputStream(sockIn); + in = new DataInputStream(bufIn); + magic = in.readInt(); + + } catch (IOException e) { + throw new RemoteException("Error HTTP-unwrapping call", + e); + } + } + // bufIn's mark will invalidate itself when it overflows + // so it doesn't have to be turned off + // read and verify transport header short version = in.readShort(); if (magic != TransportConstants.Magic || diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 684b0cab3ab..696c9cd270f 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -191,6 +191,8 @@ java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java 7146541 linux-al java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java 7191877 generic-all +sun/rmi/transport/proxy/EagerHttpFallback.java 7195095 generic-all + java/rmi/activation/Activatable/extLoadedImpl/ext.sh 8062724 generic-all sun/rmi/rmic/newrmic/equivalence/run.sh 8145980 generic-all diff --git a/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java b/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java new file mode 100644 index 00000000000..8999c3d7310 --- /dev/null +++ b/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * + * @summary HttpSocket functionality test + * @author Dana Burns + * + * @library ../../testlibrary + * @modules java.rmi/sun.rmi.registry + * java.rmi/sun.rmi.server + * java.rmi/sun.rmi.transport + * java.rmi/sun.rmi.transport.proxy + * java.rmi/sun.rmi.transport.tcp + * @build TestLibrary HttpSocketTest HttpSocketTest_Stub + * @run main/othervm/policy=security.policy HttpSocketTest + */ + +/* + * This test assures remote methods can be carried out over RMI. + * After setting the RMI runtime socket factory to the http proxy version, + * a registry is created, a remote object (an instance of this class) is + * registered with it, and then it is exercised. + */ + +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.Naming; +import java.rmi.RMISecurityManager; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.RMISocketFactory; +import java.rmi.server.UnicastRemoteObject; +import sun.rmi.transport.proxy.RMIHttpToPortSocketFactory; + +interface MyRemoteInterface extends Remote { + void setRemoteObject( Remote r ) throws RemoteException; + Remote getRemoteObject() throws RemoteException; +} + +public class HttpSocketTest extends UnicastRemoteObject + implements MyRemoteInterface +{ + private static final String NAME = "HttpSocketTest"; + + public HttpSocketTest() throws RemoteException{} + + private Remote ro; + + public static void main(String[] args) + throws Exception + { + + Registry registry = null; + + TestLibrary.suggestSecurityManager(null); + + // Set the socket factory. + System.err.println("installing socket factory"); + RMISocketFactory.setSocketFactory(new RMIHttpToPortSocketFactory()); + int registryPort = -1; + + try { + System.err.println("Starting registry"); + registry = TestLibrary.createRegistryOnUnusedPort(); + registryPort = TestLibrary.getRegistryPort(registry); + } catch (Exception e) { + TestLibrary.bomb(e); + } + + try { + registry.rebind( NAME, new HttpSocketTest() ); + MyRemoteInterface httpTest = + (MyRemoteInterface)Naming.lookup("//:" + registryPort + "/" + NAME); + httpTest.setRemoteObject( new HttpSocketTest() ); + Remote r = httpTest.getRemoteObject(); + + } catch (Exception e) { + TestLibrary.bomb(e); + } + + + } + + public void setRemoteObject( Remote ro ) throws RemoteException { + this.ro = ro; + } + + public Remote getRemoteObject() throws RemoteException { + return( this.ro ); + } + +} diff --git a/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java b/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java new file mode 100644 index 00000000000..03757a3df20 --- /dev/null +++ b/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +// Stub class generated by rmic, do not edit. +// Contents subject to change without notice. + +public final class HttpSocketTest_Stub + extends java.rmi.server.RemoteStub + implements MyRemoteInterface, java.rmi.Remote +{ + private static final java.rmi.server.Operation[] operations = { + new java.rmi.server.Operation("java.rmi.Remote getRemoteObject()"), + new java.rmi.server.Operation("void setRemoteObject(java.rmi.Remote)") + }; + + private static final long interfaceHash = 3775375480010579665L; + + private static final long serialVersionUID = 2; + + private static boolean useNewInvoke; + private static java.lang.reflect.Method $method_getRemoteObject_0; + private static java.lang.reflect.Method $method_setRemoteObject_1; + + static { + try { + java.rmi.server.RemoteRef.class.getMethod("invoke", + new java.lang.Class[] { + java.rmi.Remote.class, + java.lang.reflect.Method.class, + java.lang.Object[].class, + long.class + }); + useNewInvoke = true; + $method_getRemoteObject_0 = MyRemoteInterface.class.getMethod("getRemoteObject", new java.lang.Class[] {}); + $method_setRemoteObject_1 = MyRemoteInterface.class.getMethod("setRemoteObject", new java.lang.Class[] {java.rmi.Remote.class}); + } catch (java.lang.NoSuchMethodException e) { + useNewInvoke = false; + } + } + + // constructors + public HttpSocketTest_Stub() { + super(); + } + public HttpSocketTest_Stub(java.rmi.server.RemoteRef ref) { + super(ref); + } + + // methods from remote interfaces + + // implementation of getRemoteObject() + public java.rmi.Remote getRemoteObject() + throws java.rmi.RemoteException + { + try { + if (useNewInvoke) { + Object $result = ref.invoke(this, $method_getRemoteObject_0, null, -2578437860804964265L); + return ((java.rmi.Remote) $result); + } else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash); + ref.invoke(call); + java.rmi.Remote $result; + try { + java.io.ObjectInput in = call.getInputStream(); + $result = (java.rmi.Remote) in.readObject(); + } catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } catch (java.lang.ClassNotFoundException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } finally { + ref.done(call); + } + return $result; + } + } catch (java.lang.RuntimeException e) { + throw e; + } catch (java.rmi.RemoteException e) { + throw e; + } catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + // implementation of setRemoteObject(Remote) + public void setRemoteObject(java.rmi.Remote $param_Remote_1) + throws java.rmi.RemoteException + { + try { + if (useNewInvoke) { + ref.invoke(this, $method_setRemoteObject_1, new java.lang.Object[] {$param_Remote_1}, -7518632118115022871L); + } else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_Remote_1); + } catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + ref.done(call); + } + } catch (java.lang.RuntimeException e) { + throw e; + } catch (java.rmi.RemoteException e) { + throw e; + } catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } +} diff --git a/jdk/test/java/rmi/transport/httpSocket/security.policy b/jdk/test/java/rmi/transport/httpSocket/security.policy new file mode 100644 index 00000000000..f1960c9772d --- /dev/null +++ b/jdk/test/java/rmi/transport/httpSocket/security.policy @@ -0,0 +1,10 @@ + +grant { + permission java.net.SocketPermission "*:1024-", "accept,connect,listen"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.proxy"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp"; + permission java.lang.RuntimePermission "setFactory"; +}; diff --git a/jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java b/jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java new file mode 100644 index 00000000000..5449c3b8759 --- /dev/null +++ b/jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8023862 + * @summary Verify that the default value of the java.rmi.server.disableHttp + * has been changed from false to true. + * @modules java.rmi/sun.rmi.transport.proxy + * @compile -XDignore.symbol.file DisableHttpDefaultValue.java + * + * @run main/othervm DisableHttpDefaultValue true + * @run main/othervm -Djava.rmi.server.disableHttp DisableHttpDefaultValue false + * @run main/othervm -Djava.rmi.server.disableHttp=false DisableHttpDefaultValue false + * @run main/othervm -Djava.rmi.server.disableHttp=xyzzy DisableHttpDefaultValue false + * @run main/othervm -Djava.rmi.server.disableHttp=true DisableHttpDefaultValue true + */ + +import sun.rmi.transport.proxy.RMIMasterSocketFactory; + +public class DisableHttpDefaultValue { + /** + * Subclass RMIMasterSocketFactory to get access to + * protected field altFactoryList. This list has a + * zero size if proxying is disabled. + */ + static class SocketFactory extends RMIMasterSocketFactory { + boolean proxyDisabled() { + return altFactoryList.size() == 0; + } + } + + /** + * Takes a single arg, which is the expected boolean value of + * java.rmi.server.disableHttp. + */ + public static void main(String[] args) throws Exception { + // Force there to be a proxy host, so that we are able to + // tell whether proxying is enabled or disabled. + System.setProperty("http.proxyHost", "proxy.example.com"); + + String propval = System.getProperty("java.rmi.server.disableHttp"); + String propdisp = (propval == null) ? "null" : ("\"" + propval + "\""); + boolean expected = Boolean.parseBoolean(args[0]); + boolean actual = new SocketFactory().proxyDisabled(); + System.out.printf("### prop=%s exp=%s act=%s%n", propdisp, expected, actual); + if (expected != actual) + throw new AssertionError(); + } +} diff --git a/jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java b/jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java new file mode 100644 index 00000000000..5b5691701c7 --- /dev/null +++ b/jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4290727 + * @summary Verify that ConnectException will trigger HTTP fallback if + * sun.rmi.transport.proxy.eagerHttpFallback system property is set. + * + * @library ../../../../java/rmi/testlibrary + * @modules java.rmi/sun.rmi.registry + * java.rmi/sun.rmi.server + * java.rmi/sun.rmi.transport + * java.rmi/sun.rmi.transport.tcp + * @build TestLibrary + * @run main/othervm EagerHttpFallback + */ + +import java.rmi.*; +import java.rmi.registry.*; + +public class EagerHttpFallback { + + static final int INITIAL_PORT = TestLibrary.getUnusedRandomPort(); + static final int FALLBACK_PORT = TestLibrary.getUnusedRandomPort(); + + public static void main(String[] args) throws Exception { + System.setProperty("http.proxyHost", "127.0.0.1"); + System.setProperty("http.proxyPort", Integer.toString(FALLBACK_PORT)); + System.setProperty("sun.rmi.transport.proxy.eagerHttpFallback", + "true"); + LocateRegistry.createRegistry(FALLBACK_PORT); + + /* + * The call below should trigger a ConnectException in the + * RMIMasterSocketFactory when it attempts a direct connection to + * INITIAL_PORT, which no one is listening on. Since + * eagerHttpFallback is set, this ConnectException should trigger HTTP + * fallback, which will send a call through the HTTP proxy, which is + * configured to be localhost with a port behind which a registry is + * listening--so if fallback works properly, the list() call should + * succeed. + */ + try { + LocateRegistry.getRegistry(INITIAL_PORT).list(); + } catch (Exception e) { + System.err.println( + "call on registry stub with port " + INITIAL_PORT + + "did not successfully perform HTTP fallback to " + + FALLBACK_PORT); + throw e; + } + } +} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java b/jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java new file mode 100644 index 00000000000..7de92ee2c47 --- /dev/null +++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4203167 + * + * @summary RMI blocks in HttpAwareServerSocket.accept() if you telnet to it + * @author Adrian Colley + * + * @library ../../../../../java/rmi/testlibrary + * @modules java.rmi/sun.rmi.transport.proxy + * @build TestIface TestImpl TestImpl_Stub + * @run main/othervm/policy=security.policy/timeout=60 BlockAcceptTest + */ + +/* This test attempts to stymie the RMI accept loop. The accept loop in + * RMI endlessly accepts a connection, spawns a thread for it, and repeats. + * The accept() call can be replaced by a user-supplied library which + * might foolishly block indefinitely in its accept() method, which would + * prevent RMI from accepting other connections on that socket. + * + * Unfortunately, HttpAwareServerSocket (default server socket) is/was such + * a foolish thing. It reads 4 bytes to see if they're "POST" before + * returning. The bug fix is to move the HTTP stuff into the mainloop, + * which has the side effect of enabling it for non-default socketfactories. + * + * This test: + * 1. Creates an object and exports it. + * 2. Connects to the listening RMI port and sends nothing, to hold it up. + * 3. Makes a regular call, using HTTP tunnelling. + * 4. Fails to deadlock, thereby passing the test. + * + * Some runtime dependencies I'm trying to eliminate: + * 1. We don't know the port number until after exporting the object, but + * have to set it in http.proxyPort somehow. Hopefully http.proxyPort + * isn't read too soon or this test will fail with a ConnectException. + */ + +import java.rmi.*; +import java.rmi.server.RMISocketFactory; +import java.io.*; +import java.net.*; + +import sun.rmi.transport.proxy.RMIMasterSocketFactory; +import sun.rmi.transport.proxy.RMIHttpToPortSocketFactory; + +public class BlockAcceptTest +{ + public static void main(String[] args) + throws Exception + { + // Make trouble for ourselves + if (System.getSecurityManager() == null) + System.setSecurityManager(new RMISecurityManager()); + + // HTTP direct to the server port + System.setProperty("http.proxyHost", "127.0.0.1"); + + // Set the socket factory. + System.err.println("(installing HTTP-out socket factory)"); + HttpOutFactory fac = new HttpOutFactory(); + RMISocketFactory.setSocketFactory(fac); + + // Create remote object + TestImpl impl = new TestImpl(); + + // Export and get which port. + System.err.println("(exporting remote object)"); + TestIface stub = impl.export(); + try { + int port = fac.whichPort(); + + // Sanity + if (port == 0) + throw new Error("TEST FAILED: export didn't reserve a port(?)"); + + // Set the HTTP port, at last. + System.setProperty("http.proxyPort", port+""); + + // Now, connect to that port + //Thread.sleep(2000); + System.err.println("(connecting to listening port on 127.0.0.1:" + + port + ")"); + Socket DoS = new Socket("127.0.0.1", port); + // we hold the connection open until done with the test. + + // The test itself: make a remote call and see if it's blocked or + // if it works + //Thread.sleep(2000); + System.err.println("(making RMI-through-HTTP call)"); + System.err.println("(typical test failure deadlocks here)"); + String result = stub.testCall("dummy load"); + + System.err.println(" => " + result); + if (!("OK".equals(result))) + throw new Error("TEST FAILED: result not OK"); + System.err.println("Test passed."); + + // Clean up, including writing a byte to that connection just in + // case an optimizer thought of optimizing it out of existence + try { + DoS.getOutputStream().write(0); + DoS.getOutputStream().close(); + } catch (Throwable apathy) { + } + + } finally { + try { + impl.unexport(); + } catch (Throwable unmatter) { + } + } + + // Should exit here + } + + private static class HttpOutFactory + extends RMISocketFactory + { + private int servport = 0; + + public Socket createSocket(String h, int p) + throws IOException + { + return ((new RMIHttpToPortSocketFactory()).createSocket(h, p)); + } + + /** Create a server socket and remember which port it's on. + * Aborts if createServerSocket(0) is called twice, because then + * it doesn't know whether to remember the first or second port. + */ + public ServerSocket createServerSocket(int p) + throws IOException + { + ServerSocket ss; + ss = (new RMIMasterSocketFactory()).createServerSocket(p); + if (p == 0) { + if (servport != 0) { + System.err.println("TEST FAILED: " + + "Duplicate createServerSocket(0)"); + throw new Error("Test aborted (createServerSocket)"); + } + servport = ss.getLocalPort(); + } + return (ss); + } + + /** Return which port was reserved by createServerSocket(0). + * If the return value was 0, createServerSocket(0) wasn't called. + */ + public int whichPort() { + return (servport); + } + } // end class HttpOutFactory +} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java new file mode 100644 index 00000000000..85bab51483d --- /dev/null +++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * 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.rmi.*; + +public interface TestIface + extends Remote +{ + public String testCall(String ign) + throws RemoteException; +} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java new file mode 100644 index 00000000000..73601a9e3b6 --- /dev/null +++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * 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.rmi.*; +import java.rmi.server.*; + +public class TestImpl + extends Object + implements TestIface +{ + public TestImpl() { + } + + public TestIface export() + throws RemoteException + { + return (TestIface)UnicastRemoteObject.exportObject(this); + } + + public void unexport() + throws NoSuchObjectException + { + UnicastRemoteObject.unexportObject(this, true); + } + + public String testCall(String ign) { + return ("OK"); + } +} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java new file mode 100644 index 00000000000..2de40012e16 --- /dev/null +++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +// Stub class generated by rmic, do not edit. +// Contents subject to change without notice. + +public final class TestImpl_Stub + extends java.rmi.server.RemoteStub + implements TestIface +{ + private static final long serialVersionUID = 2; + + private static java.lang.reflect.Method $method_testCall_0; + + static { + try { + $method_testCall_0 = TestIface.class.getMethod("testCall", new java.lang.Class[] {java.lang.String.class}); + } catch (java.lang.NoSuchMethodException e) { + throw new java.lang.NoSuchMethodError( + "stub class initialization failed"); + } + } + + // constructors + public TestImpl_Stub(java.rmi.server.RemoteRef ref) { + super(ref); + } + + // methods from remote interfaces + + // implementation of testCall(String) + public java.lang.String testCall(java.lang.String $param_String_1) + throws java.rmi.RemoteException + { + try { + Object $result = ref.invoke(this, $method_testCall_0, new java.lang.Object[] {$param_String_1}, -4495720265115653109L); + return ((java.lang.String) $result); + } catch (java.lang.RuntimeException e) { + throw e; + } catch (java.rmi.RemoteException e) { + throw e; + } catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } +} diff --git a/jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy b/jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy new file mode 100644 index 00000000000..a8c8d0a64d8 --- /dev/null +++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy @@ -0,0 +1,10 @@ +grant { + // Take this out once we can specify -Djava.security.debug on + // the run line and figure out what else is needed + permission java.security.AllPermission; + + permission java.net.SocketPermission "*:1024-65535", "connect,listen"; + permission java.util.PropertyPermission "http.proxyHost", "write"; + permission java.util.PropertyPermission "http.proxyPort", "write"; + permission java.lang.RuntimePermission "setFactory"; +}; From 1af2806677f4cc6854607c45c7f65f3b12636411 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Tue, 26 Apr 2016 18:30:00 -0700 Subject: [PATCH 152/222] 8154556: Use java.nio.ByteOrder instead of boolean value Reviewed-by: alanb --- .../java/lang/invoke/MethodHandles.java | 68 ++++++++++--------- .../VarHandleTestAccessBoolean.java | 1 - .../VarHandles/VarHandleTestAccessByte.java | 1 - .../VarHandles/VarHandleTestAccessChar.java | 1 - .../VarHandles/VarHandleTestAccessDouble.java | 1 - .../VarHandles/VarHandleTestAccessFloat.java | 1 - .../VarHandles/VarHandleTestAccessInt.java | 1 - .../VarHandles/VarHandleTestAccessLong.java | 1 - .../VarHandles/VarHandleTestAccessShort.java | 1 - .../VarHandles/VarHandleTestAccessString.java | 1 - .../VarHandleTestByteArrayAsChar.java | 11 +-- .../VarHandleTestByteArrayAsDouble.java | 11 +-- .../VarHandleTestByteArrayAsFloat.java | 11 +-- .../VarHandleTestByteArrayAsInt.java | 15 ++-- .../VarHandleTestByteArrayAsLong.java | 11 +-- .../VarHandleTestByteArrayAsShort.java | 11 +-- ...X-VarHandleTestByteArrayView.java.template | 10 +-- 17 files changed, 81 insertions(+), 76 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 6c37371a57b..12fcecd125d 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -25,34 +25,38 @@ package java.lang.invoke; -import java.lang.reflect.*; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Iterator; -import java.util.List; -import java.util.Arrays; -import java.util.Objects; -import java.security.AccessController; -import java.security.PrivilegedAction; - +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyAccess; import sun.invoke.util.Wrapper; -import jdk.internal.reflect.CallerSensitive; -import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; -import java.lang.invoke.LambdaForm.BasicType; -import static java.lang.invoke.MethodHandleImpl.Intrinsic; -import static java.lang.invoke.MethodHandleNatives.Constants.*; +import java.lang.invoke.LambdaForm.BasicType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ReflectPermission; +import java.nio.ByteOrder; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; - +import static java.lang.invoke.MethodHandleImpl.Intrinsic; +import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; import static java.lang.invoke.MethodType.methodType; @@ -2337,13 +2341,12 @@ return mh1; * * @param viewArrayClass the view array class, with a component type of * type {@code T} - * @param bigEndian true if the endianness of the view array elements, as - * stored in the underlying {@code byte} array, is big endian, otherwise - * little endian + * @param byteOrder the endianness of the view array elements, as + * stored in the underlying {@code byte} array * @return a VarHandle giving access to elements of a {@code byte[]} array * viewed as if elements corresponding to the components type of the view * array class - * @throws NullPointerException if viewArrayClass is null + * @throws NullPointerException if viewArrayClass or byteOrder is null * @throws IllegalArgumentException if viewArrayClass is not an array type * @throws UnsupportedOperationException if the component type of * viewArrayClass is not supported as a variable type @@ -2351,8 +2354,10 @@ return mh1; */ public static VarHandle byteArrayViewVarHandle(Class viewArrayClass, - boolean bigEndian) throws IllegalArgumentException { - return VarHandles.byteArrayViewHandle(viewArrayClass, bigEndian); + ByteOrder byteOrder) throws IllegalArgumentException { + Objects.requireNonNull(byteOrder); + return VarHandles.byteArrayViewHandle(viewArrayClass, + byteOrder == ByteOrder.BIG_ENDIAN); } /** @@ -2422,14 +2427,13 @@ return mh1; * * @param viewArrayClass the view array class, with a component type of * type {@code T} - * @param bigEndian true if the endianness of the view array elements, as - * stored in the underlying {@code ByteBuffer}, is big endian, otherwise - * little endian (Note this overrides the endianness of a - * {@code ByteBuffer}) + * @param byteOrder the endianness of the view array elements, as + * stored in the underlying {@code ByteBuffer} (Note this overrides the + * endianness of a {@code ByteBuffer}) * @return a VarHandle giving access to elements of a {@code ByteBuffer} * viewed as if elements corresponding to the components type of the view * array class - * @throws NullPointerException if viewArrayClass is null + * @throws NullPointerException if viewArrayClass or byteOrder is null * @throws IllegalArgumentException if viewArrayClass is not an array type * @throws UnsupportedOperationException if the component type of * viewArrayClass is not supported as a variable type @@ -2437,8 +2441,10 @@ return mh1; */ public static VarHandle byteBufferViewVarHandle(Class viewArrayClass, - boolean bigEndian) throws IllegalArgumentException { - return VarHandles.makeByteBufferViewHandle(viewArrayClass, bigEndian); + ByteOrder byteOrder) throws IllegalArgumentException { + Objects.requireNonNull(byteOrder); + return VarHandles.makeByteBufferViewHandle(viewArrayClass, + byteOrder == ByteOrder.BIG_ENDIAN); } diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java index 5590984e493..b22fc3e182a 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java @@ -106,7 +106,6 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java index f9c9d4fc31e..088a519e920 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java @@ -106,7 +106,6 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java index bd1174efc5a..18ff6542615 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java @@ -106,7 +106,6 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java index d8732d239b4..36c84e2f753 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java @@ -106,7 +106,6 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java index 9976102d027..2ea2d9617be 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java @@ -106,7 +106,6 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java index c78e5cb7199..0c3d8d5c841 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java @@ -106,7 +106,6 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java index f82ee67960e..a034a536468 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java @@ -106,7 +106,6 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java index d235e03a7bf..4ff25cc4a5f 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java @@ -106,7 +106,6 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java index 61e3690447c..4272c898a4c 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java @@ -106,7 +106,6 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java index e6941f5fa3c..c46720b738a 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8154556 * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsChar * @run testng/othervm -Diters=20000 VarHandleTestByteArrayAsChar * @run testng/othervm -Diters=20000 -XX:-TieredCompilation VarHandleTestByteArrayAsChar @@ -57,15 +58,16 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { // Combinations of VarHandle byte[] or ByteBuffer vhss = new ArrayList<>(); for (MemoryMode endianess : Arrays.asList(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + + ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; VarHandleSource aeh = new VarHandleSource( - MethodHandles.byteArrayViewVarHandle(char[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteArrayViewVarHandle(char[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( - MethodHandles.byteBufferViewVarHandle(char[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteBufferViewVarHandle(char[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(bbh); } @@ -93,7 +95,6 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java index ec4b843b2aa..9cee7930dee 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8154556 * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsDouble * @run testng/othervm -Diters=20000 VarHandleTestByteArrayAsDouble * @run testng/othervm -Diters=20000 -XX:-TieredCompilation VarHandleTestByteArrayAsDouble @@ -57,15 +58,16 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { // Combinations of VarHandle byte[] or ByteBuffer vhss = new ArrayList<>(); for (MemoryMode endianess : Arrays.asList(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + + ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; VarHandleSource aeh = new VarHandleSource( - MethodHandles.byteArrayViewVarHandle(double[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteArrayViewVarHandle(double[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( - MethodHandles.byteBufferViewVarHandle(double[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteBufferViewVarHandle(double[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(bbh); } @@ -93,7 +95,6 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java index 57d37cbe523..e366e84c239 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8154556 * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsFloat * @run testng/othervm -Diters=20000 VarHandleTestByteArrayAsFloat * @run testng/othervm -Diters=20000 -XX:-TieredCompilation VarHandleTestByteArrayAsFloat @@ -57,15 +58,16 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { // Combinations of VarHandle byte[] or ByteBuffer vhss = new ArrayList<>(); for (MemoryMode endianess : Arrays.asList(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + + ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; VarHandleSource aeh = new VarHandleSource( - MethodHandles.byteArrayViewVarHandle(float[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteArrayViewVarHandle(float[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( - MethodHandles.byteBufferViewVarHandle(float[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteBufferViewVarHandle(float[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(bbh); } @@ -93,7 +95,6 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java index ae66477d3b6..2831fa63210 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8154556 * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsInt * @run testng/othervm -Diters=20000 VarHandleTestByteArrayAsInt * @run testng/othervm -Diters=20000 -XX:-TieredCompilation VarHandleTestByteArrayAsInt @@ -37,10 +38,10 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; -import java.util.EnumSet; import java.util.List; -import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { static final int SIZE = Integer.BYTES; @@ -57,15 +58,16 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { // Combinations of VarHandle byte[] or ByteBuffer vhss = new ArrayList<>(); for (MemoryMode endianess : Arrays.asList(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + + ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; VarHandleSource aeh = new VarHandleSource( - MethodHandles.byteArrayViewVarHandle(int[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteArrayViewVarHandle(int[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( - MethodHandles.byteBufferViewVarHandle(int[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteBufferViewVarHandle(int[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(bbh); } @@ -93,7 +95,6 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java index ac08db2af5c..263245a5e72 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8154556 * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsLong * @run testng/othervm -Diters=20000 VarHandleTestByteArrayAsLong * @run testng/othervm -Diters=20000 -XX:-TieredCompilation VarHandleTestByteArrayAsLong @@ -57,15 +58,16 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { // Combinations of VarHandle byte[] or ByteBuffer vhss = new ArrayList<>(); for (MemoryMode endianess : Arrays.asList(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + + ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; VarHandleSource aeh = new VarHandleSource( - MethodHandles.byteArrayViewVarHandle(long[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteArrayViewVarHandle(long[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( - MethodHandles.byteBufferViewVarHandle(long[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteBufferViewVarHandle(long[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(bbh); } @@ -93,7 +95,6 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java index 9742fbd2522..3d6078e6056 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8154556 * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsShort * @run testng/othervm -Diters=20000 VarHandleTestByteArrayAsShort * @run testng/othervm -Diters=20000 -XX:-TieredCompilation VarHandleTestByteArrayAsShort @@ -57,15 +58,16 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { // Combinations of VarHandle byte[] or ByteBuffer vhss = new ArrayList<>(); for (MemoryMode endianess : Arrays.asList(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + + ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; VarHandleSource aeh = new VarHandleSource( - MethodHandles.byteArrayViewVarHandle(short[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteArrayViewVarHandle(short[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( - MethodHandles.byteBufferViewVarHandle(short[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteBufferViewVarHandle(short[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(bbh); } @@ -93,7 +95,6 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); - assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); diff --git a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template index 1c323e2f195..4cdf45bad80 100644 --- a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template +++ b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template @@ -23,6 +23,7 @@ /* * @test + * @bug 8154556 * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAs$Type$ * @run testng/othervm -Diters=20000 VarHandleTestByteArrayAs$Type$ * @run testng/othervm -Diters=20000 -XX:-TieredCompilation VarHandleTestByteArrayAs$Type$ @@ -57,15 +58,16 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { // Combinations of VarHandle byte[] or ByteBuffer vhss = new ArrayList<>(); for (MemoryMode endianess : Arrays.asList(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + + ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; VarHandleSource aeh = new VarHandleSource( - MethodHandles.byteArrayViewVarHandle($type$[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteArrayViewVarHandle($type$[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( - MethodHandles.byteBufferViewVarHandle($type$[].class, - endianess == MemoryMode.BIG_ENDIAN), + MethodHandles.byteBufferViewVarHandle($type$[].class, bo), endianess, MemoryMode.READ_WRITE); vhss.add(bbh); } From 27f82bea87acd8eab8235837c0e2512291fab590 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Tue, 26 Apr 2016 18:42:51 -0700 Subject: [PATCH 153/222] 8154447: Exempt classes under java.util.concurrent from MH.Lookup restrictions Reviewed-by: mchung, martin --- .../java/lang/invoke/MethodHandles.java | 9 ++-- .../invoke/JavaUtilConcurrentLookupTest.java | 46 +++++++++++++++++++ .../java/util/concurrent/LookupTester.java | 37 +++++++++++++++ 3 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 jdk/test/java/lang/invoke/JavaUtilConcurrentLookupTest.java create mode 100644 jdk/test/java/lang/invoke/java.base/java/util/concurrent/LookupTester.java diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 12fcecd125d..afe6aecc9f4 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -745,10 +745,13 @@ public class MethodHandles { if (name.startsWith("java.lang.invoke.")) throw newIllegalArgumentException("illegal lookupClass: "+lookupClass); - // For caller-sensitive MethodHandles.lookup() - // disallow lookup more restricted packages + // For caller-sensitive MethodHandles.lookup() disallow lookup from + // restricted packages. This a fragile and blunt approach. + // TODO replace with a more formal and less fragile mechanism + // that does not bluntly restrict classes under packages within + // java.base from looking up MethodHandles or VarHandles. if (allowedModes == ALL_MODES && lookupClass.getClassLoader() == null) { - if (name.startsWith("java.") || + if ((name.startsWith("java.") && !name.startsWith("java.util.concurrent.")) || (name.startsWith("sun.") && !name.startsWith("sun.invoke."))) { throw newIllegalArgumentException("illegal lookupClass: " + lookupClass); } diff --git a/jdk/test/java/lang/invoke/JavaUtilConcurrentLookupTest.java b/jdk/test/java/lang/invoke/JavaUtilConcurrentLookupTest.java new file mode 100644 index 00000000000..9715de8fd46 --- /dev/null +++ b/jdk/test/java/lang/invoke/JavaUtilConcurrentLookupTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 Tests that Lookup can be produced from classes under java.util.concurrent + * @bug 8154447 + * @compile/module=java.base java/util/concurrent/LookupTester.java + * @run testng/othervm JavaUtilConcurrentLookupTest + */ + +import org.testng.annotations.Test; + +import java.util.concurrent.LookupTester; + +public class JavaUtilConcurrentLookupTest { + + @Test + public void testLookup() { + LookupTester.getLookup(); + } + + @Test + public void testLookupIn() { + LookupTester.getLookupIn(); + } +} diff --git a/jdk/test/java/lang/invoke/java.base/java/util/concurrent/LookupTester.java b/jdk/test/java/lang/invoke/java.base/java/util/concurrent/LookupTester.java new file mode 100644 index 00000000000..2198495fcac --- /dev/null +++ b/jdk/test/java/lang/invoke/java.base/java/util/concurrent/LookupTester.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util.concurrent; + +import java.lang.invoke.MethodHandles; + +public class LookupTester { + public static MethodHandles.Lookup getLookup() { + return MethodHandles.lookup(); + } + + + public static MethodHandles.Lookup getLookupIn() { + return MethodHandles.lookup().in(ConcurrentHashMap.class); + } +} From 75b0c4fb9ccda0e42acfc363fd8d2d850b52cf59 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Wed, 27 Apr 2016 09:13:51 +0200 Subject: [PATCH 154/222] 8155156: Remove remaining sun.misc.* imports from the jdk repo Reviewed-by: chegar --- .../share/classes/sun/nio/ch/AbstractPollSelectorImpl.java | 3 +-- .../java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java | 3 +-- jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java index 6f1f8e86f04..81fa9836a87 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * 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,7 +29,6 @@ import java.io.IOException; import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; -import sun.misc.*; /** diff --git a/jdk/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java b/jdk/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java index 1911c3507c0..27c7a41937e 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java +++ b/jdk/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * 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,7 +29,6 @@ import java.io.IOException; import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; -import sun.misc.*; /** diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index aa460f9f636..9ff2d7ce598 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -52,7 +52,6 @@ import sun.awt.*; import sun.awt.datatransfer.DataTransferer; import sun.font.FontConfigManager; import sun.java2d.SunGraphicsEnvironment; -import sun.misc.*; import sun.awt.util.PerformanceLogger; import sun.awt.util.ThreadGroupUtils; import sun.print.PrintJob2D; From 10ed386bc7daa5d524902c1aba7e25ee3c61a143 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Wed, 27 Apr 2016 21:00:45 +0900 Subject: [PATCH 155/222] 8155089: UL: Remove trailing comma from log decoration list Reviewed-by: dsamersoff, mlarsson --- hotspot/src/share/vm/logging/logConfiguration.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp index 870e7c0eabd..de0cce51d3d 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.cpp +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp @@ -408,10 +408,12 @@ void LogConfiguration::describe_current_configuration(outputStream* out){ out->print_cr("Log output configuration:"); for (size_t i = 0; i < _n_outputs; i++) { out->print("#" SIZE_FORMAT ": %s %s ", i, _outputs[i]->name(), _outputs[i]->config_string()); + char delimiter[2] = {0}; for (size_t d = 0; d < LogDecorators::Count; d++) { LogDecorators::Decorator decorator = static_cast(d); if (_outputs[i]->decorators().is_decorator(decorator)) { - out->print("%s,", LogDecorators::name(decorator)); + out->print("%s%s", delimiter, LogDecorators::name(decorator)); + *delimiter = ','; } } out->cr(); From 59144619a147605a4091b5d23ff96d9e113b0761 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 27 Apr 2016 14:30:32 +0200 Subject: [PATCH 156/222] 8154841: Let different Jib profiles have different default make targets Reviewed-by: dholmes, tbell --- common/conf/jib-profiles.js | 88 +++++++++++++++++++++++++++---------- make/Init.gmk | 7 ++- make/Jprt.gmk | 4 +- make/Main.gmk | 10 +++-- 4 files changed, 79 insertions(+), 30 deletions(-) diff --git a/common/conf/jib-profiles.js b/common/conf/jib-profiles.js index 9ca454e51d1..39196ac553a 100644 --- a/common/conf/jib-profiles.js +++ b/common/conf/jib-profiles.js @@ -212,14 +212,17 @@ var getJibProfiles = function (input) { * @returns Common values */ var getJibProfilesCommon = function (input) { - var common = { - dependencies: ["boot_jdk", "gnumake", "jtreg"], - configure_args: ["--with-default-make-target=all", "--enable-jtreg-failure-handler"], - configure_args_32bit: ["--with-target-bits=32", "--with-jvm-variants=client,server"], - configure_args_debug: ["--enable-debug"], - configure_args_slowdebug: ["--with-debug-level=slowdebug"], - organization: "jpg.infra.builddeps" - }; + var common = {}; + + common.dependencies = ["boot_jdk", "gnumake", "jtreg"], + common.default_make_targets = ["product-images", "test-image"], + common.default_make_targets_debug = common.default_make_targets; + common.default_make_targets_slowdebug = common.default_make_targets; + common.configure_args = ["--enable-jtreg-failure-handler"], + common.configure_args_32bit = ["--with-target-bits=32", "--with-jvm-variants=client,server"], + common.configure_args_debug = ["--enable-debug"], + common.configure_args_slowdebug = ["--with-debug-level=slowdebug"], + common.organization = "jpg.infra.builddeps" return common; }; @@ -241,8 +244,8 @@ var getJibProfilesProfiles = function (input, common) { target_os: "linux", target_cpu: "x64", dependencies: concat(common.dependencies, "devkit"), - configure_args: concat(common.configure_args, "--with-zlib=system"), - make_args: common.make_args + configure_args: concat(common.configure_args, "--with-zlib=system"), + default_make_targets: concat(common.default_make_targets, "docs-image") }, "linux-x86": { @@ -252,39 +255,39 @@ var getJibProfilesProfiles = function (input, common) { dependencies: concat(common.dependencies, "devkit"), configure_args: concat(common.configure_args, common.configure_args_32bit, "--with-zlib=system"), - make_args: common.make_args + default_make_targets: common.default_make_targets }, "macosx-x64": { target_os: "macosx", target_cpu: "x64", dependencies: concat(common.dependencies, "devkit"), - configure_args: concat(common.configure_args, "--with-zlib=system"), - make_args: common.make_args + configure_args: concat(common.configure_args, "--with-zlib=system"), + default_make_targets: common.default_make_targets }, "solaris-x64": { target_os: "solaris", target_cpu: "x64", dependencies: concat(common.dependencies, "devkit", "cups"), - configure_args: concat(common.configure_args, "--with-zlib=system"), - make_args: common.make_args + configure_args: concat(common.configure_args, "--with-zlib=system"), + default_make_targets: common.default_make_targets }, "solaris-sparcv9": { target_os: "solaris", target_cpu: "sparcv9", dependencies: concat(common.dependencies, "devkit", "cups"), - configure_args: concat(common.configure_args, "--with-zlib=system"), - make_args: common.make_args + configure_args: concat(common.configure_args, "--with-zlib=system"), + default_make_targets: common.default_make_targets }, "windows-x64": { target_os: "windows", target_cpu: "x64", dependencies: concat(common.dependencies, "devkit", "freetype"), - configure_args: common.configure_args, - make_args: common.make_args + configure_args: concat(common.configure_args), + default_make_targets: common.default_make_targets }, "windows-x86": { @@ -293,7 +296,7 @@ var getJibProfilesProfiles = function (input, common) { build_cpu: "x64", dependencies: concat(common.dependencies, "devkit", "freetype"), configure_args: concat(common.configure_args, common.configure_args_32bit), - make_args: common.make_args + default_make_targets: common.default_make_targets } }; profiles = concatObjects(profiles, mainProfiles); @@ -306,14 +309,15 @@ var getJibProfilesProfiles = function (input, common) { // implementation builds. var openOnlyProfiles = generateOpenOnlyProfiles(common, mainProfiles); // The open only profiles on linux are used for reference builds and should - // produce the compact profile images by default. + // produce the compact profile images by default. This adds "profiles" as an + // extra default target. var openOnlyProfilesExtra = { "linux-x64-open": { - configure_args: ["--with-default-make-target=all profiles"], + default_make_targets: "profiles" }, "linux-x86-open": { - configure_args: ["--with-default-make-target=all profiles"], + default_make_targets: "profiles" } }; var openOnlyProfiles = concatObjects(openOnlyProfiles, openOnlyProfilesExtra); @@ -336,6 +340,7 @@ var getJibProfilesProfiles = function (input, common) { // Generate the missing platform attributes profiles = generatePlatformAttributes(profiles); + profiles = generateDefaultMakeTargetsConfigureArg(common, profiles); return profiles; }; @@ -469,6 +474,8 @@ var generateDebugProfiles = function (common, profiles) { var debugProfile = profile + "-debug"; newProfiles[debugProfile] = clone(profiles[profile]); newProfiles[debugProfile].debug_level = "fastdebug"; + newProfiles[debugProfile].default_make_targets + = common.default_make_targets_debug; newProfiles[debugProfile].labels = concat(newProfiles[debugProfile].labels || [], "debug"), newProfiles[debugProfile].configure_args @@ -492,6 +499,8 @@ var generateSlowdebugProfiles = function (common, profiles) { var debugProfile = profile + "-slowdebug"; newProfiles[debugProfile] = clone(profiles[profile]); newProfiles[debugProfile].debug_level = "slowdebug"; + newProfiles[debugProfile].default_make_targets + = common.default_make_targets_slowdebug; newProfiles[debugProfile].labels = concat(newProfiles[debugProfile].labels || [], "slowdebug"), newProfiles[debugProfile].configure_args @@ -523,6 +532,39 @@ var generateOpenOnlyProfiles = function (common, profiles) { return newProfiles; }; +/** + * The default_make_targets attribute on a profile is not a real Jib attribute. + * This function rewrites that attribute into the corresponding configure arg. + * Calling this function multiple times on the same profiles object is safe. + * + * @param common Common values + * @param profiles Profiles map to rewrite profiles for + * @returns {{}} New map of profiles with the make targets converted + */ +var generateDefaultMakeTargetsConfigureArg = function (common, profiles) { + var ret = concatObjects(profiles, {}); + for (var profile in ret) { + if (ret[profile]["default_make_targets"] != null) { + var targetsString = concat(ret[profile].default_make_targets).join(" "); + // Iterate over all configure args and see if --with-default-make-target + // is already there and change it, otherwise add it. + var found = false; + for (var arg in ret[profile].configure_args) { + if (arg.startsWith("--with-default-make-target")) { + found = true; + arg.replace(/=.*/, "=" + targetsString); + } + } + if (!found) { + ret[profile].configure_args = concat( + ret[profile].configure_args, + "--with-default-make-target=" + targetsString); + } + } + } + return ret; +} + /** * Deep clones an object tree. * diff --git a/make/Init.gmk b/make/Init.gmk index ee67aeaa65f..6ed612b28a2 100644 --- a/make/Init.gmk +++ b/make/Init.gmk @@ -268,8 +268,13 @@ else # HAS_SPEC=true ############################################################################## MAIN_TARGETS := $(SEQUENTIAL_TARGETS) $(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE) + # If building the default target, add what they are to the description. + DESCRIPTION_TARGETS := $(strip $(MAIN_TARGETS)) + ifeq ($(DESCRIPTION_TARGETS), default) + DESCRIPTION_TARGETS += ($(DEFAULT_MAKE_TARGET)) + endif TARGET_DESCRIPTION := target$(if $(word 2, $(MAIN_TARGETS)),s) \ - '$(strip $(MAIN_TARGETS))' in configuration '$(CONF_NAME)' + '$(strip $(DESCRIPTION_TARGETS))' in configuration '$(CONF_NAME)' # MAKEOVERRIDES is automatically set and propagated by Make to sub-Make calls. # We need to clear it of the init-specific variables. The user-specified diff --git a/make/Jprt.gmk b/make/Jprt.gmk index e7eba24bd31..e82b84d5e11 100644 --- a/make/Jprt.gmk +++ b/make/Jprt.gmk @@ -108,8 +108,8 @@ SRC_JDK_MACOSX_BUNDLE_DIR := $(JDK_MACOSX_BUNDLE_DIR) SRC_JRE_MACOSX_BUNDLE_DIR := $(JRE_MACOSX_BUNDLE_DIR) # Bundle up the images -JPRT_TARGET ?= all -ifeq ($(JPRT_TARGET), all) +JPRT_TARGET ?= default +ifeq ($(JPRT_TARGET), default) bundles: $(JPRT_TARGET) @$(call TargetEnter) $(MKDIR) -p $(BUILD_OUTPUT)/bundles diff --git a/make/Main.gmk b/make/Main.gmk index a693465ec4d..3d596817c08 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -340,10 +340,10 @@ docs-javadoc: docs-jvmtidoc: +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk jvmtidocs) -zip-docs: docs-javadoc docs-jvmtidoc +zip-docs: +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk zip-docs) -ALL_TARGETS += docs-javadoc docs-jvmtidoc +ALL_TARGETS += docs-javadoc docs-jvmtidoc zip-docs ################################################################################ # Cross compilation support @@ -602,6 +602,8 @@ else docs-jvmtidoc: hotspot + zip-docs: docs-javadoc docs-jvmtidoc + test: jimages test-image create-buildjdk-copy: jdk.jlink-java java.base-gendata @@ -703,7 +705,7 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) endif # This target builds the documentation image -docs-image: zip-docs +docs-image: docs-javadoc docs-jvmtidoc # This target builds the test image test-image: prepare-test-image test-image-hotspot-jtreg-native \ @@ -727,7 +729,7 @@ images: product-images docs: docs-image all: all-images -ALL_TARGETS += default jdk images docs all zip-docs +ALL_TARGETS += default jdk images docs all ################################################################################ ################################################################################ From fe4860fe5e30b4db33ad51861b1a3c7e79a78307 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Wed, 27 Apr 2016 15:01:21 +0200 Subject: [PATCH 157/222] 8155214: java/lang/invoke/PermuteArgsTest.java fails due to exhausted code cache Reviewed-by: sundar --- jdk/test/java/lang/invoke/PermuteArgsTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/jdk/test/java/lang/invoke/PermuteArgsTest.java b/jdk/test/java/lang/invoke/PermuteArgsTest.java index edb9ba33bc7..a47e4d7fc54 100644 --- a/jdk/test/java/lang/invoke/PermuteArgsTest.java +++ b/jdk/test/java/lang/invoke/PermuteArgsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* @test * @summary unit tests for method handles which permute their arguments + * @library /lib/testlibrary/jsr292 /lib/testlibrary * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -ea -esa -DPermuteArgsTest.MAX_ARITY=8 test.java.lang.invoke.PermuteArgsTest */ /* Examples of manual runs: @@ -36,6 +37,8 @@ package test.java.lang.invoke; import org.testng.*; import org.testng.annotations.*; +import com.oracle.testlibrary.jsr292.CodeCacheOverflowProcessor; + import java.util.*; import java.lang.reflect.*; @@ -122,9 +125,15 @@ public class PermuteArgsTest { } new PermuteArgsTest().test(); } + static int testCases; + @Test public void test() throws Throwable { + CodeCacheOverflowProcessor.runMHTest(this::test0); + } + + public void test0() throws Throwable { testCases = 0; Lookup lookup = lookup(); for (Method m : lookup.lookupClass().getDeclaredMethods()) { From 5881148f01f2a5b97c5d475ca08d746812c990e7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 27 Apr 2016 15:50:33 +0200 Subject: [PATCH 158/222] 8134503: support ES6 parsing in Nashorn Reviewed-by: jlaskey, sundar, mhaupt --- .../internal/codegen/CodeGenerator.java | 2 +- .../internal/codegen/CompilationPhase.java | 4 +- .../internal/codegen/SplitIntoFunctions.java | 4 +- .../nashorn/internal/codegen/WeighNodes.java | 2 +- .../jdk/nashorn/internal/ir/AccessNode.java | 25 +- .../jdk/nashorn/internal/ir/BaseNode.java | 24 +- .../jdk/nashorn/internal/ir/Block.java | 50 +- .../jdk/nashorn/internal/ir/ClassNode.java | 147 + .../nashorn/internal/ir/ExpressionList.java | 87 + .../jdk/nashorn/internal/ir/ForNode.java | 1 - .../jdk/nashorn/internal/ir/FunctionNode.java | 264 +- .../jdk/nashorn/internal/ir/IdentNode.java | 95 + .../jdk/nashorn/internal/ir/IndexNode.java | 25 +- .../jdk/nashorn/internal/ir/Module.java | 338 +++ .../jdk/nashorn/internal/ir/PropertyNode.java | 54 +- .../ir/visitor/NodeOperatorVisitor.java | 16 +- .../internal/ir/visitor/NodeVisitor.java | 19 + .../jdk/nashorn/internal/parser/Parser.java | 2425 +++++++++++++++-- .../internal/parser/ParserContext.java | 7 +- .../parser/ParserContextFunctionNode.java | 84 +- .../parser/ParserContextModuleNode.java | 90 + .../nashorn/internal/parser/TokenType.java | 9 +- .../jdk/nashorn/internal/runtime/Context.java | 4 +- .../runtime/resources/Messages.properties | 21 + .../classes/jdk/nashorn/tools/Shell.java | 3 + .../basic/{yield.js => es6/parser-es6.js} | 80 +- ...function_mult_params_in_strict.js.EXPECTED | 4 +- .../script/nosecurity/parserapi.js.EXPECTED | 22 +- .../nosecurity/parserapi_strict.js.EXPECTED | 4 +- .../treeapi/array_literal.js.EXPECTED | 2 +- .../treeapi/objectLiteral.js.EXPECTED | 10 +- .../nosecurity/treeapi/property.js.EXPECTED | 8 +- .../nosecurity/treeapi/throw.js.EXPECTED | 2 +- .../nosecurity/treeapi/with.js.EXPECTED | 2 +- .../test/framework/ScriptRunnable.java | 4 +- 35 files changed, 3524 insertions(+), 414 deletions(-) create mode 100644 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ClassNode.java create mode 100644 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ExpressionList.java create mode 100644 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Module.java create mode 100644 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextModuleNode.java rename nashorn/test/script/basic/{yield.js => es6/parser-es6.js} (50%) diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java index 3a60ed5f6a8..f784b74ca5f 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -4310,7 +4310,7 @@ final class CodeGenerator extends NodeOperatorVisitor { // we still use IS_SPLIT as the criteria in CompilationPhase.SERIALIZE_SPLIT_PHASE. FunctionNode.IS_ANONYMOUS | FunctionNode.USES_ANCESTOR_SCOPE | FunctionNode.IS_SPLIT, body, - null + null, + originalFn.getModule(), + originalFn.getDebugFlags() ) .setCompileUnit(lc, splitNode.getCompileUnit()); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java index 494afb4d8d7..488beb29a81 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java @@ -435,7 +435,7 @@ final class WeighNodes extends NodeOperatorVisitor { } @Override - public Node leaveBIND(final BinaryNode binaryNode) { + public Node leaveARROW(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java index 315ee395b92..d490bbbfcd0 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,12 +48,13 @@ public final class AccessNode extends BaseNode { * @param property property */ public AccessNode(final long token, final int finish, final Expression base, final String property) { - super(token, finish, base, false); + super(token, finish, base, false, false); this.property = property; } - private AccessNode(final AccessNode accessNode, final Expression base, final String property, final boolean isFunction, final Type type, final int id) { - super(accessNode, base, isFunction, type, id); + private AccessNode(final AccessNode accessNode, final Expression base, final String property, final boolean isFunction, + final Type type, final int id, final boolean isSuper) { + super(accessNode, base, isFunction, type, id, isSuper); this.property = property; } @@ -105,7 +106,7 @@ public final class AccessNode extends BaseNode { if (this.base == base) { return this; } - return new AccessNode(this, base, property, isFunction(), type, programPoint); + return new AccessNode(this, base, property, isFunction(), type, programPoint, isSuper()); } @Override @@ -113,7 +114,7 @@ public final class AccessNode extends BaseNode { if (this.type == type) { return this; } - return new AccessNode(this, base, property, isFunction(), type, programPoint); + return new AccessNode(this, base, property, isFunction(), type, programPoint, isSuper()); } @Override @@ -121,7 +122,7 @@ public final class AccessNode extends BaseNode { if (this.programPoint == programPoint) { return this; } - return new AccessNode(this, base, property, isFunction(), type, programPoint); + return new AccessNode(this, base, property, isFunction(), type, programPoint, isSuper()); } @Override @@ -129,6 +130,14 @@ public final class AccessNode extends BaseNode { if (isFunction()) { return this; } - return new AccessNode(this, base, property, true, type, programPoint); + return new AccessNode(this, base, property, true, type, programPoint, isSuper()); + } + + @Override + public AccessNode setIsSuper() { + if (isSuper()) { + return this; + } + return new AccessNode(this, base, property, isFunction(), type, programPoint, true); } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java index 4e59753a5c3..85ded3e92c2 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java @@ -52,6 +52,9 @@ public abstract class BaseNode extends Expression implements FunctionCall, Optim /** Program point id */ protected final int programPoint; + /** Super property access. */ + private final boolean isSuper; + /** * Constructor * @@ -59,13 +62,15 @@ public abstract class BaseNode extends Expression implements FunctionCall, Optim * @param finish finish * @param base base node * @param isFunction is this a function + * @param isSuper is this a super property access */ - public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction) { + public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean isSuper) { super(token, base.getStart(), finish); this.base = base; this.isFunction = isFunction; this.type = null; this.programPoint = INVALID_PROGRAM_POINT; + this.isSuper = isSuper; } /** @@ -75,13 +80,15 @@ public abstract class BaseNode extends Expression implements FunctionCall, Optim * @param isFunction is this a function * @param callSiteType the callsite type for this base node, either optimistic or conservative * @param programPoint program point id + * @param isSuper is this a super property access */ - protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final Type callSiteType, final int programPoint) { + protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final Type callSiteType, final int programPoint, final boolean isSuper) { super(baseNode); this.base = base; this.isFunction = isFunction; this.type = callSiteType; this.programPoint = programPoint; + this.isSuper = isSuper; } /** @@ -136,4 +143,17 @@ public abstract class BaseNode extends Expression implements FunctionCall, Optim */ public abstract BaseNode setIsFunction(); + /** + * @return {@code true} if a SuperProperty access. + */ + public boolean isSuper() { + return isSuper; + } + + /** + * Mark this node as being a SuperProperty access. + * + * @return a base node identical to this one in all aspects except with its super flag set. + */ + public abstract BaseNode setIsSuper(); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java index cbc0e480bf7..152269f8f0d 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java @@ -65,24 +65,39 @@ public class Block extends Node implements BreakableNode, Terminal, Flags private final LocalVariableConversion conversion; /** Flag indicating that this block needs scope */ - public static final int NEEDS_SCOPE = 1 << 0; + public static final int NEEDS_SCOPE = 1 << 0; /** * Is this block tagged as terminal based on its contents * (usually the last statement) */ - public static final int IS_TERMINAL = 1 << 2; + public static final int IS_TERMINAL = 1 << 2; /** * Is this block the eager global scope - i.e. the original program. This isn't true for the * outermost level of recompiles */ - public static final int IS_GLOBAL_SCOPE = 1 << 3; + public static final int IS_GLOBAL_SCOPE = 1 << 3; /** * Is this block a synthetic one introduced by Parser? */ - public static final int IS_SYNTHETIC = 1 << 4; + public static final int IS_SYNTHETIC = 1 << 4; + + /** + * Is this the function body block? May not be the first, if parameter list contains expressions. + */ + public static final int IS_BODY = 1 << 5; + + /** + * Is this the parameter initialization block? If present, must be the first block, immediately wrapping the function body block. + */ + public static final int IS_PARAMETER_BLOCK = 1 << 6; + + /** + * Marks the variable declaration block for case clauses of a switch statement. + */ + public static final int IS_SWITCH_BLOCK = 1 << 7; /** * Constructor @@ -489,4 +504,31 @@ public class Block extends Node implements BreakableNode, Terminal, Flags public Node accept(final NodeVisitor visitor) { return Acceptor.accept(this, visitor); } + + /** + * Checks if this is a function body. + * + * @return true if the function body flag is set + */ + public boolean isFunctionBody() { + return getFlag(IS_BODY); + } + + /** + * Checks if this is a parameter block. + * + * @return true if the parameter block flag is set + */ + public boolean isParameterBlock() { + return getFlag(IS_PARAMETER_BLOCK); + } + + /** + * Checks whether this is a switch block. + * + * @return true if this is a switch block + */ + public boolean isSwitchBlock() { + return getFlag(IS_SWITCH_BLOCK); + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ClassNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ClassNode.java new file mode 100644 index 00000000000..4c0c6ffb175 --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ClassNode.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.nashorn.internal.ir; + +import java.util.Collections; +import java.util.List; + +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; + +/** + * IR representation for class definitions. + */ +public class ClassNode extends Expression { + private static final long serialVersionUID = 1L; + + private final IdentNode ident; + private final Expression classHeritage; + private final PropertyNode constructor; + private final List classElements; + private final int line; + + /** + * Constructor. + * + * @param line line number + * @param token token + * @param finish finish + * @param ident ident + * @param classHeritage class heritage + * @param constructor constructor + * @param classElements class elements + */ + public ClassNode(final int line, final long token, final int finish, final IdentNode ident, final Expression classHeritage, final PropertyNode constructor, + final List classElements) { + super(token, finish); + this.line = line; + this.ident = ident; + this.classHeritage = classHeritage; + this.constructor = constructor; + this.classElements = classElements; + } + + /** + * Class identifier. Optional. + * + * @return the class identifier + */ + public IdentNode getIdent() { + return ident; + } + + /** + * The expression of the {@code extends} clause. Optional. + * + * @return the class heritage + */ + public Expression getClassHeritage() { + return classHeritage; + } + + /** + * Get the constructor method definition. + * + * @return the constructor + */ + public PropertyNode getConstructor() { + return constructor; + } + + /** + * Get method definitions except the constructor. + * + * @return the class elements + */ + public List getClassElements() { + return Collections.unmodifiableList(classElements); + } + + /** + * Returns the line number. + * + * @return the line number + */ + public int getLineNumber() { + return line; + } + + @Override + public Type getType() { + return Type.OBJECT; + } + + @Override + public Node accept(final NodeVisitor visitor) { + if (visitor.enterClassNode(this)) { + return visitor.leaveClassNode(this); + } + + return this; + } + + @Override + public void toString(final StringBuilder sb, final boolean printType) { + sb.append("class"); + if (ident != null) { + sb.append(' '); + ident.toString(sb, printType); + } + if (classHeritage != null) { + sb.append(" extends"); + classHeritage.toString(sb, printType); + } + sb.append(" {"); + if (constructor != null) { + constructor.toString(sb, printType); + } + for (final PropertyNode classElement : classElements) { + sb.append(" "); + classElement.toString(sb, printType); + } + sb.append("}"); + } +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ExpressionList.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ExpressionList.java new file mode 100644 index 00000000000..9410a90ed42 --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ExpressionList.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.nashorn.internal.ir; + +import java.util.Collections; +import java.util.List; + +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; + +/** + * IR for CoverParenthesizedExpressionAndArrowParameterList, used only during parsing. + */ +public final class ExpressionList extends Expression { + private static final long serialVersionUID = 1L; + + private final List expressions; + + /** + * Constructor. + * + * @param token token + * @param finish finish + * @param expressions expression + */ + public ExpressionList(final long token, final int finish, final List expressions) { + super(token, finish); + this.expressions = expressions; + } + + /** + * Get the list of expressions. + * + * @return the list of expressions + */ + public List getExpressions() { + return Collections.unmodifiableList(expressions); + } + + @Override + public Node accept(final NodeVisitor visitor) { + throw new UnsupportedOperationException(); + } + + @Override + public Type getType() { + return null; + } + + @Override + public void toString(StringBuilder sb, boolean printType) { + sb.append("("); + boolean first = true; + for (Expression expression : expressions) { + if (first) { + first = false; + } else { + sb.append(", "); + } + expression.toString(sb, printType); + } + sb.append(")"); + } +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java index 0913b9e64f0..df104340aed 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java @@ -90,7 +90,6 @@ public final class ForNode extends LoopNode { this.init = init; this.modify = modify; this.iterator = null; - } private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test, diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java index ab40c04d3b6..8eda934b542 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java @@ -69,7 +69,13 @@ public final class FunctionNode extends LexicalContextExpression implements Flag /** a getter, @see {@link UserAccessorProperty} */ GETTER, /** a setter, @see {@link UserAccessorProperty} */ - SETTER + SETTER, + /** an arrow function */ + ARROW, + /** a generator function */ + GENERATOR, + /** a module function */ + MODULE } /** Source of entity. */ @@ -122,6 +128,12 @@ public final class FunctionNode extends LexicalContextExpression implements Flag /** Root class for function */ private final Class rootClass; + /** The ES6 module */ + private final Module module; + + /** The debug flags */ + private final int debugFlags; + /** Is anonymous function flag. */ public static final int IS_ANONYMOUS = 1 << 0; @@ -172,49 +184,21 @@ public final class FunctionNode extends LexicalContextExpression implements Flag /** * Is this function the top-level program? */ - public static final int IS_PROGRAM = 1 << 13; + public static final int IS_PROGRAM = 1 << 13; /** * Flag indicating whether this function uses the local variable symbol for itself. Only named function expressions * can have this flag set if they reference themselves (e.g. "(function f() { return f })". Declared functions will * use the symbol in their parent scope instead when they reference themselves by name. */ - public static final int USES_SELF_SYMBOL = 1 << 14; + public static final int USES_SELF_SYMBOL = 1 << 14; /** Does this function use the "this" keyword? */ - public static final int USES_THIS = 1 << 15; + public static final int USES_THIS = 1 << 15; /** Is this declared in a dynamic context */ - public static final int IN_DYNAMIC_CONTEXT = 1 << 16; + public static final int IN_DYNAMIC_CONTEXT = 1 << 16; - /** - * The following flags are derived from directive comments within this function. - * Note that even IS_STRICT is one such flag but that requires special handling. - */ - - /** parser, print parse tree */ - public static final int IS_PRINT_PARSE = 1 << 17; - /** parser, print lower parse tree */ - public static final int IS_PRINT_LOWER_PARSE = 1 << 18; - /** parser, print AST */ - public static final int IS_PRINT_AST = 1 << 19; - /** parser, print lower AST */ - public static final int IS_PRINT_LOWER_AST = 1 << 20; - /** parser, print symbols */ - public static final int IS_PRINT_SYMBOLS = 1 << 21; - - // callsite tracing, profiling within this function - /** profile callsites in this function? */ - public static final int IS_PROFILE = 1 << 22; - - /** trace callsite enterexit in this function? */ - public static final int IS_TRACE_ENTEREXIT = 1 << 23; - - /** trace callsite misses in this function? */ - public static final int IS_TRACE_MISSES = 1 << 24; - - /** trace callsite values in this function? */ - public static final int IS_TRACE_VALUES = 1 << 25; /** * Whether this function needs the callee {@link ScriptFunction} instance passed to its code as a @@ -222,18 +206,41 @@ public final class FunctionNode extends LexicalContextExpression implements Flag * Rather, it is always calculated (see {@link #needsCallee()}). {@link RecompilableScriptFunctionData} * will, however, cache the value of this flag. */ - public static final int NEEDS_CALLEE = 1 << 26; + public static final int NEEDS_CALLEE = 1 << 17; /** * Is the function node cached? */ - public static final int IS_CACHED = 1 << 27; + public static final int IS_CACHED = 1 << 18; - /** extension callsite flags mask */ - public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE | - IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST | - IS_PRINT_SYMBOLS | IS_PROFILE | IS_TRACE_ENTEREXIT | - IS_TRACE_MISSES | IS_TRACE_VALUES; + /** + * Does this function contain a super call? (cf. ES6 14.3.5 Static Semantics: HasDirectSuper) + */ + public static final int ES6_HAS_DIRECT_SUPER = 1 << 19; + + /** + * Does this function use the super binding? + */ + public static final int ES6_USES_SUPER = 1 << 20; + + /** + * Is this function a (class or object) method? + */ + public static final int ES6_IS_METHOD = 1 << 21; + + /** + * Is this the constructor method? + */ + public static final int ES6_IS_CLASS_CONSTRUCTOR = 1 << 22; + + /** Is this the constructor of a subclass (i.e., a class with an extends declaration)? */ + public static final int ES6_IS_SUBCLASS_CONSTRUCTOR = 1 << 23; + + /** is this a strong mode function? */ + public static final int ES6_IS_STRONG = 1 << 24; + + /** Does this function use new.target? */ + public static final int ES6_USES_NEW_TARGET = 1 << 25; /** Does this function or any nested functions contain an eval? */ private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL; @@ -247,8 +254,44 @@ public final class FunctionNode extends LexicalContextExpression implements Flag /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval, or it's the program. */ public static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL | IS_PROGRAM; + + /** + * The following flags are derived from directive comments within this function. + * Note that even IS_STRICT is one such flag but that requires special handling. + */ + + /** parser, print parse tree */ + public static final int DEBUG_PRINT_PARSE = 1 << 0; + /** parser, print lower parse tree */ + public static final int DEBUG_PRINT_LOWER_PARSE = 1 << 1; + /** parser, print AST */ + public static final int DEBUG_PRINT_AST = 1 << 2; + /** parser, print lower AST */ + public static final int DEBUG_PRINT_LOWER_AST = 1 << 3; + /** parser, print symbols */ + public static final int DEBUG_PRINT_SYMBOLS = 1 << 4; + + // callsite tracing, profiling within this function + /** profile callsites in this function? */ + public static final int DEBUG_PROFILE = 1 << 5; + + /** trace callsite enterexit in this function? */ + public static final int DEBUG_TRACE_ENTEREXIT = 1 << 6; + + /** trace callsite misses in this function? */ + public static final int DEBUG_TRACE_MISSES = 1 << 7; + + /** trace callsite values in this function? */ + public static final int DEBUG_TRACE_VALUES = 1 << 8; + + /** extension callsite flags mask */ + public static final int DEBUG_CALLSITE_FLAGS = DEBUG_PRINT_PARSE | + DEBUG_PRINT_LOWER_PARSE | DEBUG_PRINT_AST | DEBUG_PRINT_LOWER_AST | + DEBUG_PRINT_SYMBOLS | DEBUG_PROFILE | DEBUG_TRACE_ENTEREXIT | + DEBUG_TRACE_MISSES | DEBUG_TRACE_VALUES; + /** What is the return type of this function? */ - private Type returnType = Type.UNKNOWN; + public Type returnType = Type.UNKNOWN; /** * Constructor @@ -267,6 +310,8 @@ public final class FunctionNode extends LexicalContextExpression implements Flag * @param flags initial flags * @param body body of the function * @param endParserState The parser state at the end of the parsing. + * @param module the module + * @param debugFlags the debug flags */ public FunctionNode( final Source source, @@ -282,7 +327,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag final FunctionNode.Kind kind, final int flags, final Block body, - final Object endParserState) { + final Object endParserState, + final Module module, + final int debugFlags) { super(token, finish); this.source = source; @@ -299,7 +346,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag this.body = body; this.thisProperties = 0; this.rootClass = null; - this.endParserState = endParserState; + this.endParserState = endParserState; + this.module = module; + this.debugFlags = debugFlags; } private FunctionNode( @@ -335,6 +384,8 @@ public final class FunctionNode extends LexicalContextExpression implements Flag this.ident = functionNode.ident; this.kind = functionNode.kind; this.firstToken = functionNode.firstToken; + this.module = functionNode.module; + this.debugFlags = functionNode.debugFlags; } @Override @@ -366,23 +417,23 @@ public final class FunctionNode extends LexicalContextExpression implements Flag } // quick check for extension callsite flags turned on by directives. - if ((flags & EXTENSION_CALLSITE_FLAGS) == 0) { + if ((debugFlags & DEBUG_CALLSITE_FLAGS) == 0) { return callsiteFlags; } - if (getFlag(IS_PROFILE)) { + if (getDebugFlag(DEBUG_PROFILE)) { callsiteFlags |= CALLSITE_PROFILE; } - if (getFlag(IS_TRACE_MISSES)) { + if (getDebugFlag(DEBUG_TRACE_MISSES)) { callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_MISSES; } - if (getFlag(IS_TRACE_VALUES)) { + if (getDebugFlag(DEBUG_TRACE_VALUES)) { callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT | CALLSITE_TRACE_VALUES; } - if (getFlag(IS_TRACE_ENTEREXIT)) { + if (getDebugFlag(DEBUG_TRACE_ENTEREXIT)) { callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT; } @@ -466,23 +517,23 @@ public final class FunctionNode extends LexicalContextExpression implements Flag public static int getDirectiveFlag(final String directive) { switch (directive) { case "nashorn callsite trace enterexit": - return IS_TRACE_ENTEREXIT; + return DEBUG_TRACE_ENTEREXIT; case "nashorn callsite trace misses": - return IS_TRACE_MISSES; + return DEBUG_TRACE_MISSES; case "nashorn callsite trace objects": - return IS_TRACE_VALUES; + return DEBUG_TRACE_VALUES; case "nashorn callsite profile": - return IS_PROFILE; + return DEBUG_PROFILE; case "nashorn print parse": - return IS_PRINT_PARSE; + return DEBUG_PRINT_PARSE; case "nashorn print lower parse": - return IS_PRINT_LOWER_PARSE; + return DEBUG_PRINT_LOWER_PARSE; case "nashorn print ast": - return IS_PRINT_AST; + return DEBUG_PRINT_AST; case "nashorn print lower ast": - return IS_PRINT_LOWER_AST; + return DEBUG_PRINT_LOWER_AST; case "nashorn print symbols": - return IS_PRINT_SYMBOLS; + return DEBUG_PRINT_SYMBOLS; default: // unknown/unsupported directive return 0; @@ -578,6 +629,25 @@ public final class FunctionNode extends LexicalContextExpression implements Flag return setFlags(lc, flags | flag); } + /** + * Returns the debug flags for this function. + * + * @return the debug flags + */ + public int getDebugFlags() { + return debugFlags; + } + + /** + * Checks whether a debug flag is set for this function. + * + * @param debugFlag the debug flag + * @return true if the flag is set + */ + public boolean getDebugFlag(final int debugFlag) { + return (debugFlags & debugFlag) != 0; + } + /** * Returns true if the function is the top-level program. * @return True if this function node represents the top-level program. @@ -1065,6 +1135,86 @@ public final class FunctionNode extends LexicalContextExpression implements Flag return setFlag(lc, IS_CACHED); } + /** + * Checks if the function is generated in strong mode. + * + * @return true if strong mode enabled for function + */ + public boolean isStrong() { + return getFlag(ES6_IS_STRONG); + } + + /** + * Checks if this is an ES6 method. + * + * @return true if the ES6 method flag is set + */ + public boolean isMethod() { + return getFlag(ES6_IS_METHOD); + } + + /** + * Checks if this function uses the ES6 super binding. + * + * @return true if the ES6 super flag is set + */ + public boolean usesSuper() { + return getFlag(ES6_USES_SUPER); + } + + /** + * Checks if this function directly uses the super binding. + * + * @return true if the ES6 has-direct-super flag is set + */ + public boolean hasDirectSuper() { + return getFlag(ES6_HAS_DIRECT_SUPER); + } + + /** + * Checks if this is an ES6 class constructor. + * + * @return true if the ES6 class constructor flag is set + */ + public boolean isClassConstructor() { + return getFlag(ES6_IS_CLASS_CONSTRUCTOR); + } + + /** + * Checks if this is an ES6 subclass constructor. + * + * @return true if the ES6 subclass constructor flag is set + */ + public boolean isSubclassConstructor() { + return getFlag(ES6_IS_SUBCLASS_CONSTRUCTOR); + } + + /** + * Checks if this function uses the ES6 new-targert. + * + * @return true if the ES6 new-target flag is set + */ + public boolean usesNewTarget() { + return getFlag(ES6_USES_NEW_TARGET); + } + + /** + * Checks if this is an ES6 module. + * + * @return true if this is an ES6 module + */ + public boolean isModule() { + return kind == Kind.MODULE; + } + + /** + * Returns the functions's ES6 module. + * + * @return the module, or null if this function is not part of one + */ + public Module getModule() { + return module; + } /** * Get the compile unit used to compile this function diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java index 4570181af07..28103b8ca01 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java @@ -49,6 +49,11 @@ public final class IdentNode extends Expression implements PropertyKey, Function private static final int FUTURESTRICT_NAME = 1 << 3; private static final int IS_DECLARED_HERE = 1 << 4; private static final int IS_DEAD = 1 << 5; + private static final int DIRECT_SUPER = 1 << 6; + private static final int REST_PARAMETER = 1 << 7; + private static final int PROTO_PROPERTY = 1 << 8; + private static final int DEFAULT_PARAMETER = 1 << 9; + private static final int DESTRUCTURED_PARAMETER = 1 << 10; /** Identifier. */ private final String name; @@ -382,4 +387,94 @@ public final class IdentNode extends Expression implements PropertyKey, Function public LocalVariableConversion getLocalVariableConversion() { return conversion; } + + /** + * Checks if this is a direct super identifier + * + * @return true if the direct super flag is set + */ + public boolean isDirectSuper() { + return (flags & DIRECT_SUPER) != 0; + } + + /** + * Return a new identifier with the direct super flag set. + * + * @return the new identifier + */ + public IdentNode setIsDirectSuper() { + return new IdentNode(this, name, type, flags | DIRECT_SUPER, programPoint, conversion); + } + + /** + * Checks if this is a rest parameter + * + * @return true if the rest parameter flag is set + */ + public boolean isRestParameter() { + return (flags & REST_PARAMETER) != 0; + } + + /** + * Return a new identifier with the rest parameter flag set. + * + * @return the new identifier + */ + public IdentNode setIsRestParameter() { + return new IdentNode(this, name, type, flags | REST_PARAMETER, programPoint, conversion); + } + + /** + * Checks if this is a proto property name. + * + * @return true if this is the proto property name + */ + public boolean isProtoPropertyName() { + return (flags & PROTO_PROPERTY) != 0; + } + + /** + * Return a new identifier with the proto property name flag set. + * + * @return the new identifier + */ + public IdentNode setIsProtoPropertyName() { + return new IdentNode(this, name, type, flags | PROTO_PROPERTY, programPoint, conversion); + } + + /** + * Checks whether this is a default parameter. + * + * @return true if this is a default parameter + */ + public boolean isDefaultParameter() { + return (flags & DEFAULT_PARAMETER) != 0; + } + + /** + * Return a new identifier with the default parameter flag set. + * + * @return the new identifier + */ + public IdentNode setIsDefaultParameter() { + return new IdentNode(this, name, type, flags | DEFAULT_PARAMETER, programPoint, conversion); + } + + /** + * Checks whether this is a destructured parameter. + * + * @return true if this is a destructured parameter + */ + public boolean isDestructuredParameter() { + return (flags & DESTRUCTURED_PARAMETER) != 0; + } + + /** + * Return a new identifier with the destructured parameter flag set. + * + * @return the new identifier + */ + public IdentNode setIsDestructuredParameter() { + return new IdentNode(this, name, type, flags | DESTRUCTURED_PARAMETER, programPoint, conversion); + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java index 72df1f9694a..73e220d699c 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java @@ -47,12 +47,13 @@ public final class IndexNode extends BaseNode { * @param index index for access */ public IndexNode(final long token, final int finish, final Expression base, final Expression index) { - super(token, finish, base, false); + super(token, finish, base, false, false); this.index = index; } - private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction, final Type type, final int programPoint) { - super(indexNode, base, isFunction, type, programPoint); + private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction, + final Type type, final int programPoint, final boolean isSuper) { + super(indexNode, base, isFunction, type, programPoint, isSuper); this.index = index; } @@ -101,7 +102,7 @@ public final class IndexNode extends BaseNode { if (this.base == base) { return this; } - return new IndexNode(this, base, index, isFunction(), type, programPoint); + return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper()); } /** @@ -113,7 +114,7 @@ public final class IndexNode extends BaseNode { if(this.index == index) { return this; } - return new IndexNode(this, base, index, isFunction(), type, programPoint); + return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper()); } @Override @@ -121,7 +122,7 @@ public final class IndexNode extends BaseNode { if (this.type == type) { return this; } - return new IndexNode(this, base, index, isFunction(), type, programPoint); + return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper()); } @Override @@ -129,7 +130,7 @@ public final class IndexNode extends BaseNode { if (isFunction()) { return this; } - return new IndexNode(this, base, index, true, type, programPoint); + return new IndexNode(this, base, index, true, type, programPoint, isSuper()); } @Override @@ -137,6 +138,14 @@ public final class IndexNode extends BaseNode { if (this.programPoint == programPoint) { return this; } - return new IndexNode(this, base, index, isFunction(), type, programPoint); + return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper()); + } + + @Override + public IndexNode setIsSuper() { + if (isSuper()) { + return this; + } + return new IndexNode(this, base, index, isFunction(), type, programPoint, true); } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Module.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Module.java new file mode 100644 index 00000000000..28279abbfc6 --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Module.java @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.nashorn.internal.ir; + +import java.util.List; + +/** + * ES6 Module information. + */ +public final class Module { + + /** The synthetic binding name assigned to export default declarations with unnamed expressions. */ + public static final String DEFAULT_EXPORT_BINDING_NAME = "*default*"; + + /** The {@code export default} name. */ + public static final String DEFAULT_NAME = "default"; + + /** The {@code export *} name. */ + public static final String STAR_NAME = "*"; + + /** + * A module ExportEntry record. + * + * @link http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records + */ + public static final class ExportEntry { + private final String exportName; + private final String moduleRequest; + private final String importName; + private final String localName; + + private ExportEntry(final String exportName, final String moduleRequest, final String importName, final String localName) { + this.exportName = exportName; + this.moduleRequest = moduleRequest; + this.importName = importName; + this.localName = localName; + } + + /** + * Creates a {@code export *} export entry. + * + * @param moduleRequest the module request + * @return the export entry + */ + public static ExportEntry exportStarFrom(final String moduleRequest) { + return new ExportEntry(null, moduleRequest, STAR_NAME, null); + } + + /** + * Creates a {@code export default} export entry. + * + * @return the export entry + */ + public static ExportEntry exportDefault() { + return exportDefault(DEFAULT_EXPORT_BINDING_NAME); + } + + /** + * Creates a {@code export default} export entry with a local name. + * + * @param localName the local name + * @return the export entry + */ + public static ExportEntry exportDefault(final String localName) { + return new ExportEntry(DEFAULT_NAME, null, null, localName); + } + + /** + * Creates a export entry with a local name and export name. + * + * @param exportName the export name + * @param localName the local name + * @return the export entry + */ + public static ExportEntry exportSpecifier(final String exportName, final String localName) { + return new ExportEntry(exportName, null, null, localName); + } + + /** + * Creates a export entry with an export name. + * + * @param exportName the export name + * @return the export entry + */ + public static ExportEntry exportSpecifier(final String exportName) { + return exportSpecifier(exportName, exportName); + } + + /** + * Create a copy of this entry with the specified {@code module request} string. + * + * @param moduleRequest the module request + * @return the new export entry + */ + public ExportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) { + return new ExportEntry(exportName, moduleRequest, localName, null); + } + + /** + * Returns the entry's export name. + * + * @return the export name + */ + public String getExportName() { + return exportName; + } + + /** + * Returns the entry's module request. + * + * @return the module request + */ + public String getModuleRequest() { + return moduleRequest; + } + + /** + * Returns the entry's import name. + * + * @return the import name + */ + public String getImportName() { + return importName; + } + + /** + * Returns the entry's local name. + * + * @return the local name + */ + public String getLocalName() { + return localName; + } + + @Override + public String toString() { + return "ExportEntry [exportName=" + exportName + ", moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]"; + } + } + + /** + * An ImportEntry record. + * + * @link http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records + */ + public static final class ImportEntry { + private final String moduleRequest; + private final String importName; + private final String localName; + + private ImportEntry(final String moduleRequest, final String importName, final String localName) { + this.moduleRequest = moduleRequest; + this.importName = importName; + this.localName = localName; + } + + /** + * Creates an import entry with default name. + * + * @param localName the local name + * @return the import entry + */ + public static ImportEntry importDefault(final String localName) { + return new ImportEntry(null, DEFAULT_NAME, localName); + } + + /** + * Creates an import entry with {@code *} import name. + * + * @param localName the local name + * @return the import entry + */ + public static ImportEntry importStarAsNameSpaceFrom(final String localName) { + return new ImportEntry(null, STAR_NAME, localName); + } + + /** + * Creates an import entry with the given import and local names. + * + * @param importName the import name + * @param localName the local name + * @return the import entry + */ + public static ImportEntry importSpecifier(final String importName, final String localName) { + return new ImportEntry(null, importName, localName); + } + + /** + * Creates a new import entry with the given import name. + * + * @param importName the import name + * @return the import entry + */ + public static ImportEntry importSpecifier(final String importName) { + return importSpecifier(importName, importName); + } + + /** + * Returns a copy of this import entry with the given module request. + * + * @param moduleRequest the module request + * @return the new import entry + */ + public ImportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) { + return new ImportEntry(moduleRequest, importName, localName); + } + + /** + * Returns the entry's module request. + * + * @return the module request + */ + public String getModuleRequest() { + return moduleRequest; + } + + /** + * Returns the entry's import name. + * + * @return the import name + */ + public String getImportName() { + return importName; + } + + /** + * Returns the entry's local name. + * + * @return the local name + */ + public String getLocalName() { + return localName; + } + + @Override + public String toString() { + return "ImportEntry [moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]"; + } + } + + private final List requestedModules; + private final List importEntries; + private final List localExportEntries; + private final List indirectExportEntries; + private final List starExportEntries; + + /** + * Creates a module with the specified requested modules and import and export entries. + * + * @param requestedModules the requested modules + * @param importEntries the import entries + * @param localExportEntries local export entries + * @param indirectExportEntries indirect export entries + * @param starExportEntries star export entries + */ + public Module(final List requestedModules, final List importEntries, final List localExportEntries, + final List indirectExportEntries, final List starExportEntries) { + this.requestedModules = requestedModules; + this.importEntries = importEntries; + this.localExportEntries = localExportEntries; + this.indirectExportEntries = indirectExportEntries; + this.starExportEntries = starExportEntries; + } + + /** + * Returns the list of requested modules. + * + * @return the requested modules + */ + public List getRequestedModules() { + return requestedModules; + } + + /** + * Returns the list of import entries. + * + * @return the import entries + */ + public List getImportEntries() { + return importEntries; + } + + /** + * Returns the list of local export entries. + * + * @return the local export entries + */ + public List getLocalExportEntries() { + return localExportEntries; + } + + /** + * Returns the list of indirect export entries. + * + * @return the indirect export entries + */ + public List getIndirectExportEntries() { + return indirectExportEntries; + } + + /** + * Returns the list of star export entries. + * + * @return the star export entries + */ + public List getStarExportEntries() { + return starExportEntries; + } + + @Override + public String toString() { + return "Module [requestedModules=" + requestedModules + ", importEntries=" + importEntries + ", localExportEntries=" + localExportEntries + ", indirectExportEntries=" + + indirectExportEntries + ", starExportEntries=" + starExportEntries + "]"; + } +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java index b9b8abea500..d27bfa710b6 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java @@ -36,7 +36,7 @@ public final class PropertyNode extends Node { private static final long serialVersionUID = 1L; /** Property key. */ - private final PropertyKey key; + private final Expression key; /** Property value. */ private final Expression value; @@ -47,6 +47,12 @@ public final class PropertyNode extends Node { /** Property getter. */ private final FunctionNode setter; + /** static property flag */ + private final boolean isStatic; + + /** Computed property flag */ + private final boolean computed; + /** * Constructor * @@ -56,21 +62,27 @@ public final class PropertyNode extends Node { * @param value the value of this property * @param getter getter function body * @param setter setter function body + * @param isStatic is this a static property? + * @param computed is this a computed property? */ - public PropertyNode(final long token, final int finish, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) { + public PropertyNode(final long token, final int finish, final Expression key, final Expression value, final FunctionNode getter, final FunctionNode setter, final boolean isStatic, final boolean computed) { super(token, finish); this.key = key; this.value = value; this.getter = getter; this.setter = setter; + this.isStatic = isStatic; + this.computed = computed; } - private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) { + private PropertyNode(final PropertyNode propertyNode, final Expression key, final Expression value, final FunctionNode getter, final FunctionNode setter, final boolean isStatic, final boolean computed) { super(propertyNode); this.key = key; this.value = value; this.getter = getter; this.setter = setter; + this.isStatic = isStatic; + this.computed = computed; } /** @@ -78,14 +90,14 @@ public final class PropertyNode extends Node { * @return key name */ public String getKeyName() { - return key.getPropertyName(); + return key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : null; } @Override public Node accept(final NodeVisitor visitor) { if (visitor.enterPropertyNode(this)) { return visitor.leavePropertyNode( - setKey((PropertyKey)((Node)key).accept(visitor)). + setKey((Expression) key.accept(visitor)). setValue(value == null ? null : (Expression)value.accept(visitor)). setGetter(getter == null ? null : (FunctionNode)getter.accept(visitor)). setSetter(setter == null ? null : (FunctionNode)setter.accept(visitor))); @@ -134,7 +146,7 @@ public final class PropertyNode extends Node { if (this.getter == getter) { return this; } - return new PropertyNode(this, key, value, getter, setter); + return new PropertyNode(this, key, value, getter, setter, isStatic, computed); } /** @@ -142,14 +154,14 @@ public final class PropertyNode extends Node { * @return the key */ public Expression getKey() { - return (Expression)key; + return key; } - private PropertyNode setKey(final PropertyKey key) { + private PropertyNode setKey(final Expression key) { if (this.key == key) { return this; } - return new PropertyNode(this, key, value, getter, setter); + return new PropertyNode(this, key, value, getter, setter, isStatic, computed); } /** @@ -169,7 +181,7 @@ public final class PropertyNode extends Node { if (this.setter == setter) { return this; } - return new PropertyNode(this, key, value, getter, setter); + return new PropertyNode(this, key, value, getter, setter, isStatic, computed); } /** @@ -189,6 +201,24 @@ public final class PropertyNode extends Node { if (this.value == value) { return this; } - return new PropertyNode(this, key, value, getter, setter); - } + return new PropertyNode(this, key, value, getter, setter, isStatic, computed); + } + + /** + * Returns true if this is a static property. + * + * @return true if static flag is set + */ + public boolean isStatic() { + return isStatic; + } + + /** + * Returns true if this is a computed property. + * + * @return true if the computed flag is set + */ + public boolean isComputed() { + return computed; + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java index 9badcf6b9ca..136e5e0bcfd 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java @@ -133,8 +133,8 @@ public abstract class NodeOperatorVisitor extends Node return enterASSIGN_SHR(binaryNode); case ASSIGN_SUB: return enterASSIGN_SUB(binaryNode); - case BIND: - return enterBIND(binaryNode); + case ARROW: + return enterARROW(binaryNode); case BIT_AND: return enterBIT_AND(binaryNode); case BIT_OR: @@ -217,8 +217,8 @@ public abstract class NodeOperatorVisitor extends Node return leaveASSIGN_SHR(binaryNode); case ASSIGN_SUB: return leaveASSIGN_SUB(binaryNode); - case BIND: - return leaveBIND(binaryNode); + case ARROW: + return leaveARROW(binaryNode); case BIT_AND: return leaveBIT_AND(binaryNode); case BIT_OR: @@ -735,22 +735,22 @@ public abstract class NodeOperatorVisitor extends Node } /** - * Binary enter - callback for entering a bind operator + * Binary enter - callback for entering a arrow operator * * @param binaryNode the node * @return true if traversal should continue and node children be traversed, false otherwise */ - public boolean enterBIND(final BinaryNode binaryNode) { + public boolean enterARROW(final BinaryNode binaryNode) { return enterDefault(binaryNode); } /** - * Binary leave - callback for leaving a bind operator + * Binary leave - callback for leaving a arrow operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leaveBIND(final BinaryNode binaryNode) { + public Node leaveARROW(final BinaryNode binaryNode) { return leaveDefault(binaryNode); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java index adee3673ee4..c83587c34d4 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java @@ -33,6 +33,7 @@ import jdk.nashorn.internal.ir.BreakNode; import jdk.nashorn.internal.ir.CallNode; import jdk.nashorn.internal.ir.CaseNode; import jdk.nashorn.internal.ir.CatchNode; +import jdk.nashorn.internal.ir.ClassNode; import jdk.nashorn.internal.ir.ContinueNode; import jdk.nashorn.internal.ir.DebuggerNode; import jdk.nashorn.internal.ir.EmptyNode; @@ -897,5 +898,23 @@ public abstract class NodeVisitor { return leaveDefault(withNode); } + /** + * Callback for entering a ClassNode + * + * @param classNode the node + * @return true if traversal should continue and node children be traversed, false otherwise + */ + public boolean enterClassNode(final ClassNode classNode) { + return enterDefault(classNode); + } + /** + * Callback for leaving a ClassNode + * + * @param classNode the node + * @return processed node, which will replace the original one, or the original node + */ + public Node leaveClassNode(final ClassNode classNode) { + return leaveDefault(classNode); + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java index 5009c6f5e0e..1608d912606 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java @@ -28,35 +28,55 @@ package jdk.nashorn.internal.parser; import static jdk.nashorn.internal.codegen.CompilerConstants.ANON_FUNCTION_PREFIX; import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL; import static jdk.nashorn.internal.codegen.CompilerConstants.PROGRAM; +import static jdk.nashorn.internal.parser.TokenType.ARROW; import static jdk.nashorn.internal.parser.TokenType.ASSIGN; import static jdk.nashorn.internal.parser.TokenType.CASE; import static jdk.nashorn.internal.parser.TokenType.CATCH; +import static jdk.nashorn.internal.parser.TokenType.CLASS; import static jdk.nashorn.internal.parser.TokenType.COLON; import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT; +import static jdk.nashorn.internal.parser.TokenType.COMMENT; import static jdk.nashorn.internal.parser.TokenType.CONST; import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; import static jdk.nashorn.internal.parser.TokenType.DECPREFIX; +import static jdk.nashorn.internal.parser.TokenType.ELLIPSIS; import static jdk.nashorn.internal.parser.TokenType.ELSE; import static jdk.nashorn.internal.parser.TokenType.EOF; import static jdk.nashorn.internal.parser.TokenType.EOL; +import static jdk.nashorn.internal.parser.TokenType.EQ_STRICT; +import static jdk.nashorn.internal.parser.TokenType.ESCSTRING; +import static jdk.nashorn.internal.parser.TokenType.EXPORT; +import static jdk.nashorn.internal.parser.TokenType.EXTENDS; import static jdk.nashorn.internal.parser.TokenType.FINALLY; import static jdk.nashorn.internal.parser.TokenType.FUNCTION; import static jdk.nashorn.internal.parser.TokenType.IDENT; import static jdk.nashorn.internal.parser.TokenType.IF; +import static jdk.nashorn.internal.parser.TokenType.IMPORT; import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; import static jdk.nashorn.internal.parser.TokenType.LBRACE; +import static jdk.nashorn.internal.parser.TokenType.LBRACKET; import static jdk.nashorn.internal.parser.TokenType.LET; import static jdk.nashorn.internal.parser.TokenType.LPAREN; +import static jdk.nashorn.internal.parser.TokenType.MUL; +import static jdk.nashorn.internal.parser.TokenType.PERIOD; import static jdk.nashorn.internal.parser.TokenType.RBRACE; import static jdk.nashorn.internal.parser.TokenType.RBRACKET; import static jdk.nashorn.internal.parser.TokenType.RPAREN; import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; +import static jdk.nashorn.internal.parser.TokenType.SPREAD_ARRAY; +import static jdk.nashorn.internal.parser.TokenType.STATIC; +import static jdk.nashorn.internal.parser.TokenType.STRING; +import static jdk.nashorn.internal.parser.TokenType.SUPER; import static jdk.nashorn.internal.parser.TokenType.TEMPLATE; import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD; import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE; import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL; import static jdk.nashorn.internal.parser.TokenType.TERNARY; +import static jdk.nashorn.internal.parser.TokenType.VAR; +import static jdk.nashorn.internal.parser.TokenType.VOID; import static jdk.nashorn.internal.parser.TokenType.WHILE; +import static jdk.nashorn.internal.parser.TokenType.YIELD; +import static jdk.nashorn.internal.parser.TokenType.YIELD_STAR; import java.io.Serializable; import java.util.ArrayDeque; @@ -68,6 +88,8 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.Namespace; import jdk.nashorn.internal.ir.AccessNode; @@ -79,11 +101,13 @@ import jdk.nashorn.internal.ir.BreakNode; import jdk.nashorn.internal.ir.CallNode; import jdk.nashorn.internal.ir.CaseNode; import jdk.nashorn.internal.ir.CatchNode; +import jdk.nashorn.internal.ir.ClassNode; import jdk.nashorn.internal.ir.ContinueNode; import jdk.nashorn.internal.ir.DebuggerNode; import jdk.nashorn.internal.ir.EmptyNode; import jdk.nashorn.internal.ir.ErrorNode; import jdk.nashorn.internal.ir.Expression; +import jdk.nashorn.internal.ir.ExpressionList; import jdk.nashorn.internal.ir.ExpressionStatement; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; @@ -92,7 +116,9 @@ import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.JoinPredecessorExpression; import jdk.nashorn.internal.ir.LabelNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.Module; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; import jdk.nashorn.internal.ir.PropertyKey; @@ -110,6 +136,7 @@ import jdk.nashorn.internal.ir.WhileNode; import jdk.nashorn.internal.ir.WithNode; import jdk.nashorn.internal.ir.debug.ASTWriter; import jdk.nashorn.internal.ir.debug.PrintVisitor; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.JSErrorType; @@ -253,6 +280,14 @@ public class Parser extends AbstractParser implements Loggable { return parse(PROGRAM.symbolName(), 0, source.getLength(), false); } + /** + * Set up first token. Skips opening EOL. + */ + private void scanFirstToken() { + k = -1; + next(); + } + /** * Execute parse and return the resulting function node. * Errors will be thrown and the error manager will contain information @@ -280,9 +315,7 @@ public class Parser extends AbstractParser implements Loggable { lexer.line = lexer.pendingLine = lineOffset + 1; line = lineOffset; - // Set up first token (skips opening EOL.) - k = -1; - next(); + scanFirstToken(); // Begin parse. return program(scriptName, allowPropertyFunction); } catch (final Exception e) { @@ -300,6 +333,44 @@ public class Parser extends AbstractParser implements Loggable { } } + /** + * Parse and return the resulting module. + * Errors will be thrown and the error manager will contain information + * if parsing should fail + * + * @param moduleName name for the module, given to the parsed FunctionNode + * @param startPos start position in source + * @param len length of parse + * + * @return function node resulting from successful parse + */ + public FunctionNode parseModule(final String moduleName, final int startPos, final int len) { + try { + stream = new TokenStream(); + lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null); + lexer.line = lexer.pendingLine = lineOffset + 1; + line = lineOffset; + + scanFirstToken(); + // Begin parse. + return module(moduleName); + } catch (final Exception e) { + handleParseException(e); + + return null; + } + } + + /** + * Entry point for parsing a module. + * + * @param moduleName the module name + * @return the parsed module + */ + public FunctionNode parseModule(final String moduleName) { + return parseModule(moduleName, 0, source.getLength()); + } + /** * Parse and return the list of function parameter list. A comma * separated list of function parameter identifiers is expected to be parsed. @@ -314,11 +385,9 @@ public class Parser extends AbstractParser implements Loggable { stream = new TokenStream(); lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6); - // Set up first token (skips opening EOL.) - k = -1; - next(); + scanFirstToken(); - return formalParameterList(TokenType.EOF); + return formalParameterList(TokenType.EOF, false); } catch (final Exception e) { handleParseException(e); return null; @@ -339,9 +408,7 @@ public class Parser extends AbstractParser implements Loggable { lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6); final int functionLine = line; - // Set up first token (skips opening EOL.) - k = -1; - next(); + scanFirstToken(); // Make a fake token for the function. final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); @@ -432,7 +499,7 @@ public class Parser extends AbstractParser implements Loggable { } // Skip to a recovery point. -loop: + loop: while (true) { switch (type) { case EOF: @@ -474,7 +541,7 @@ loop: sb.append(ident.getName()); final String name = namespace.uniqueName(sb.toString()); - assert parentFunction != null || name.equals(PROGRAM.symbolName()) || name.startsWith(RecompilableScriptFunctionData.RECOMPILATION_PREFIX) : "name = " + name; + assert parentFunction != null || name.equals(PROGRAM.symbolName()) : "name = " + name; int flags = 0; if (isStrictMode) { @@ -489,7 +556,8 @@ loop: return functionNode; } - private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List parameters, final FunctionNode.Kind kind, final int functionLine, final Block body){ + private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List parameters, final FunctionNode.Kind kind, final int functionLine, final Block body) { + // assert body.isFunctionBody() || body.getFlag(Block.IS_PARAMETER_BLOCK) && ((BlockStatement) body.getLastStatement()).getBlock().isFunctionBody(); // Start new block. final FunctionNode functionNode = new FunctionNode( @@ -506,7 +574,9 @@ loop: kind, function.getFlags(), body, - function.getEndParserState()); + function.getEndParserState(), + function.getModule(), + function.getDebugFlags()); printAST(functionNode); @@ -544,23 +614,39 @@ loop: expect(RBRACE); } - final int flags = newBlock.getFlags() | (needsBraces? 0 : Block.IS_SYNTHETIC); + final int flags = newBlock.getFlags() | (needsBraces ? 0 : Block.IS_SYNTHETIC); return new Block(blockToken, finish, flags, newBlock.getStatements()); } + /** + * Get the statements in a case clause. + */ + private List caseStatementList() { + final ParserContextBlockNode newBlock = newBlock(); + try { + statementList(); + } finally { + restoreBlock(newBlock); + } + return newBlock.getStatements(); + } /** * Get all the statements generated by a single statement. * @return Statements. */ private Block getStatement() { + return getStatement(false); + } + + private Block getStatement(boolean labelledStatement) { if (type == LBRACE) { return getBlock(true); } // Set up new block. Captures first token. final ParserContextBlockNode newBlock = newBlock(); try { - statement(false, false, true); + statement(false, false, true, labelledStatement); } finally { restoreBlock(newBlock); } @@ -576,6 +662,9 @@ loop: if (EVAL.symbolName().equals(name)) { markEval(lc); + } else if (SUPER.getName().equals(name)) { + assert ident.isDirectSuper(); + markSuperCall(lc); } } @@ -585,7 +674,8 @@ loop: */ private void detectSpecialProperty(final IdentNode ident) { if (isArguments(ident)) { - lc.getCurrentFunction().setFlag(FunctionNode.USES_ARGUMENTS); + // skip over arrow functions, e.g. function f() { return (() => arguments.length)(); } + getCurrentNonArrowFunction().setFlag(FunctionNode.USES_ARGUMENTS); } } @@ -593,11 +683,15 @@ loop: return env._es6; } + private boolean isES6() { + return env._es6; + } + private static boolean isArguments(final String name) { return ARGUMENTS_NAME.equals(name); } - private static boolean isArguments(final IdentNode ident) { + static boolean isArguments(final IdentNode ident) { return isArguments(ident.getName()); } @@ -634,20 +728,20 @@ loop: case ASSIGN_SHL: case ASSIGN_SHR: case ASSIGN_SUB: - if (!(lhs instanceof AccessNode || - lhs instanceof IndexNode || - lhs instanceof IdentNode)) { - return referenceError(lhs, rhs, env._early_lvalue_error); - } - if (lhs instanceof IdentNode) { if (!checkIdentLValue((IdentNode)lhs)) { return referenceError(lhs, rhs, false); } - verifyStrictIdent((IdentNode)lhs, "assignment"); + verifyIdent((IdentNode)lhs, "assignment"); + break; + } else if (lhs instanceof AccessNode || lhs instanceof IndexNode) { + break; + } else if (opType == ASSIGN && isDestructuringLhs(lhs)) { + verifyDestructuringAssignmentPattern(lhs, "assignment"); + break; + } else { + return referenceError(lhs, rhs, env._early_lvalue_error); } - break; - default: break; } @@ -659,6 +753,114 @@ loop: return new BinaryNode(op, lhs, rhs); } + private boolean isDestructuringLhs(Expression lhs) { + if (lhs instanceof ObjectNode || lhs instanceof LiteralNode.ArrayLiteralNode) { + return isES6(); + } + return false; + } + + private void verifyDestructuringAssignmentPattern(Expression pattern, String contextString) { + assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode; + pattern.accept(new NodeVisitor(new LexicalContext()) { + @Override + public boolean enterLiteralNode(LiteralNode literalNode) { + if (literalNode.isArray()) { + boolean restElement = false; + for (Expression element : literalNode.getElementExpressions()) { + if (element != null) { + if (restElement) { + throw error(String.format("Unexpected element after rest element"), element.getToken()); + } + if (element.isTokenType(SPREAD_ARRAY)) { + restElement = true; + Expression lvalue = ((UnaryNode) element).getExpression(); + if (!checkValidLValue(lvalue, contextString)) { + throw error(AbstractParser.message("invalid.lvalue"), lvalue.getToken()); + } + } + element.accept(this); + } + } + return false; + } else { + return enterDefault(literalNode); + } + } + + @Override + public boolean enterObjectNode(ObjectNode objectNode) { + return true; + } + + @Override + public boolean enterPropertyNode(PropertyNode propertyNode) { + if (propertyNode.getValue() != null) { + propertyNode.getValue().accept(this); + return false; + } else { + return enterDefault(propertyNode); + } + } + + @Override + public boolean enterIdentNode(IdentNode identNode) { + verifyIdent(identNode, contextString); + if (!checkIdentLValue(identNode)) { + referenceError(identNode, null, true); + return false; + } + return false; + } + + @Override + public boolean enterAccessNode(AccessNode accessNode) { + return false; + } + + @Override + public boolean enterIndexNode(IndexNode indexNode) { + return false; + } + + @Override + public boolean enterBinaryNode(BinaryNode binaryNode) { + if (binaryNode.isTokenType(ASSIGN)) { + binaryNode.lhs().accept(this); + // Initializer(rhs) can be any AssignmentExpression + return false; + } else { + return enterDefault(binaryNode); + } + } + + @Override + public boolean enterUnaryNode(UnaryNode unaryNode) { + if (unaryNode.isTokenType(SPREAD_ARRAY)) { + // rest element + return true; + } else { + return enterDefault(unaryNode); + } + } + + @Override + protected boolean enterDefault(Node node) { + throw error(String.format("unexpected node in AssignmentPattern: %s", node)); + } + }); + } + + private static Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) { + final TokenType opType = Token.descType(op); + + // Build up node. + if (BinaryNode.isLogical(opType)) { + return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); + } + return new BinaryNode(op, lhs, rhs); + } + /** * Reduce increment/decrement to simpler operations. @@ -717,7 +919,7 @@ loop: restoreBlock(body); body.setFlag(Block.NEEDS_SCOPE); - final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC, body.getStatements()); + final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements()); lc.pop(script); script.setLastToken(token); @@ -776,7 +978,7 @@ loop: try { // Get the next element. - statement(true, allowPropertyFunction, false); + statement(true, allowPropertyFunction, false, false); allowPropertyFunction = false; // check for directive prologues @@ -816,16 +1018,16 @@ loop: // verify that function name as well as parameter names // satisfy strict mode restrictions. - verifyStrictIdent(function.getIdent(), "function name"); + verifyIdent(function.getIdent(), "function name"); for (final IdentNode param : function.getParameters()) { - verifyStrictIdent(param, "function parameter"); + verifyIdent(param, "function parameter"); } } } else if (Context.DEBUG) { - final int flag = FunctionNode.getDirectiveFlag(directive); - if (flag != 0) { + final int debugFlag = FunctionNode.getDirectiveFlag(directive); + if (debugFlag != 0) { final ParserContextFunctionNode function = lc.getCurrentFunction(); - function.setFlag(flag); + function.setDebugFlag(debugFlag); } } } @@ -849,29 +1051,53 @@ loop: } /** + * Parse any of the basic statement types. + * * Statement : - * Block + * BlockStatement * VariableStatement * EmptyStatement * ExpressionStatement * IfStatement - * IterationStatement + * BreakableStatement * ContinueStatement * BreakStatement * ReturnStatement * WithStatement * LabelledStatement - * SwitchStatement * ThrowStatement * TryStatement * DebuggerStatement * - * see 12 + * BreakableStatement : + * IterationStatement + * SwitchStatement * - * Parse any of the basic statement types. + * BlockStatement : + * Block + * + * Block : + * { StatementList opt } + * + * StatementList : + * StatementListItem + * StatementList StatementListItem + * + * StatementItem : + * Statement + * Declaration + * + * Declaration : + * HoistableDeclaration + * ClassDeclaration + * LexicalDeclaration + * + * HoistableDeclaration : + * FunctionDeclaration + * GeneratorDeclaration */ private void statement() { - statement(false, false, false); + statement(false, false, false, false); } /** @@ -879,14 +1105,7 @@ loop: * @param allowPropertyFunction allow property "get" and "set" functions? * @param singleStatement are we in a single statement context? */ - private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) { - if (type == FUNCTION) { - // As per spec (ECMA section 12), function declarations as arbitrary statement - // is not "portable". Implementation can issue a warning or disallow the same. - functionExpression(true, topLevel); - return; - } - + private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement, final boolean labelledStatement) { switch (type) { case LBRACE: block(); @@ -918,9 +1137,6 @@ loop: case RETURN: returnStatement(); break; - case YIELD: - yieldStatement(); - break; case WITH: withStatement(); break; @@ -941,13 +1157,32 @@ loop: case EOF: expect(SEMICOLON); break; + case FUNCTION: + // As per spec (ECMA section 12), function declarations as arbitrary statement + // is not "portable". Implementation can issue a warning or disallow the same. + if (singleStatement) { + // ES6 B.3.2 Labelled Function Declarations + // It is a Syntax Error if any strict mode source code matches this rule: + // LabelledItem : FunctionDeclaration. + if (!labelledStatement || isStrictMode) { + throw error(AbstractParser.message("expected.stmt", "function declaration"), token); + } + } + functionExpression(true, topLevel || labelledStatement); + return; default: - if (useBlockScope() && (type == LET || type == CONST)) { + if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(false) || type == CONST)) { if (singleStatement) { throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token); } variableStatement(type); break; + } else if (type == CLASS && isES6()) { + if (singleStatement) { + throw error(AbstractParser.message("expected.stmt", "class declaration"), token); + } + classDeclaration(false); + break; } if (env._const_as_var && type == CONST) { variableStatement(TokenType.VAR); @@ -963,11 +1198,11 @@ loop: final String ident = (String)getValue(); final long propertyToken = token; final int propertyLine = line; - if("get".equals(ident)) { + if ("get".equals(ident)) { next(); addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine)); return; - } else if("set".equals(ident)) { + } else if ("set".equals(ident)) { next(); addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine)); return; @@ -985,6 +1220,267 @@ loop: functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn)); } + /** + * ClassDeclaration[Yield, Default] : + * class BindingIdentifier[?Yield] ClassTail[?Yield] + * [+Default] class ClassTail[?Yield] + */ + private ClassNode classDeclaration(boolean isDefault) { + int classLineNumber = line; + + ClassNode classExpression = classExpression(!isDefault); + + if (!isDefault) { + VarNode classVar = new VarNode(classLineNumber, classExpression.getToken(), classExpression.getIdent().getFinish(), classExpression.getIdent(), classExpression, VarNode.IS_CONST); + appendStatement(classVar); + } + return classExpression; + } + + /** + * ClassExpression[Yield] : + * class BindingIdentifier[?Yield]opt ClassTail[?Yield] + */ + private ClassNode classExpression(boolean isStatement) { + assert type == CLASS; + int classLineNumber = line; + long classToken = token; + next(); + + IdentNode className = null; + if (isStatement || type == IDENT) { + className = getIdent(); + } + + return classTail(classLineNumber, classToken, className); + } + + private static final class ClassElementKey { + private final boolean isStatic; + private final String propertyName; + + private ClassElementKey(boolean isStatic, String propertyName) { + this.isStatic = isStatic; + this.propertyName = propertyName; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (isStatic ? 1231 : 1237); + result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ClassElementKey) { + ClassElementKey other = (ClassElementKey) obj; + return this.isStatic == other.isStatic && Objects.equals(this.propertyName, other.propertyName); + } + return false; + } + } + + /** + * Parse ClassTail and ClassBody. + * + * ClassTail[Yield] : + * ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } + * ClassHeritage[Yield] : + * extends LeftHandSideExpression[?Yield] + * + * ClassBody[Yield] : + * ClassElementList[?Yield] + * ClassElementList[Yield] : + * ClassElement[?Yield] + * ClassElementList[?Yield] ClassElement[?Yield] + * ClassElement[Yield] : + * MethodDefinition[?Yield] + * static MethodDefinition[?Yield] + * ; + */ + private ClassNode classTail(final int classLineNumber, final long classToken, final IdentNode className) { + final boolean oldStrictMode = isStrictMode; + isStrictMode = true; + try { + Expression classHeritage = null; + if (type == EXTENDS) { + next(); + classHeritage = leftHandSideExpression(); + } + + expect(LBRACE); + + PropertyNode constructor = null; + final ArrayList classElements = new ArrayList<>(); + final Map keyToIndexMap = new HashMap<>(); + for (;;) { + if (type == SEMICOLON) { + next(); + continue; + } + if (type == RBRACE) { + break; + } + final long classElementToken = token; + boolean isStatic = false; + if (type == STATIC) { + isStatic = true; + next(); + } + boolean generator = false; + if (isES6() && type == MUL) { + generator = true; + next(); + } + final PropertyNode classElement = methodDefinition(isStatic, classHeritage != null, generator); + if (classElement.isComputed()) { + classElements.add(classElement); + } else if (!classElement.isStatic() && classElement.getKeyName().equals("constructor")) { + if (constructor == null) { + constructor = classElement; + } else { + throw error(AbstractParser.message("multiple.constructors"), classElementToken); + } + } else { + // Check for duplicate method definitions and combine accessor methods. + // In ES6, a duplicate is never an error regardless of strict mode (in consequence of computed property names). + + final ClassElementKey key = new ClassElementKey(classElement.isStatic(), classElement.getKeyName()); + final Integer existing = keyToIndexMap.get(key); + + if (existing == null) { + keyToIndexMap.put(key, classElements.size()); + classElements.add(classElement); + } else { + final PropertyNode existingProperty = classElements.get(existing); + + final Expression value = classElement.getValue(); + final FunctionNode getter = classElement.getGetter(); + final FunctionNode setter = classElement.getSetter(); + + if (value != null || existingProperty.getValue() != null) { + keyToIndexMap.put(key, classElements.size()); + classElements.add(classElement); + } else if (getter != null) { + assert existingProperty.getGetter() != null || existingProperty.getSetter() != null; + classElements.set(existing, existingProperty.setGetter(getter)); + } else if (setter != null) { + assert existingProperty.getGetter() != null || existingProperty.getSetter() != null; + classElements.set(existing, existingProperty.setSetter(setter)); + } + } + } + } + + final long lastToken = token; + expect(RBRACE); + + if (constructor == null) { + constructor = createDefaultClassConstructor(classLineNumber, classToken, lastToken, className, classHeritage != null); + } + + classElements.trimToSize(); + return new ClassNode(classLineNumber, classToken, finish, className, classHeritage, constructor, classElements); + } finally { + isStrictMode = oldStrictMode; + } + } + + private PropertyNode createDefaultClassConstructor(int classLineNumber, long classToken, long lastToken, IdentNode className, boolean subclass) { + final int ctorFinish = finish; + final List statements; + final List parameters; + final long identToken = Token.recast(classToken, TokenType.IDENT); + if (subclass) { + final IdentNode superIdent = createIdentNode(identToken, ctorFinish, SUPER.getName()).setIsDirectSuper(); + final IdentNode argsIdent = createIdentNode(identToken, ctorFinish, "args").setIsRestParameter(); + final Expression spreadArgs = new UnaryNode(Token.recast(classToken, TokenType.SPREAD_ARGUMENT), argsIdent); + final CallNode superCall = new CallNode(classLineNumber, classToken, ctorFinish, superIdent, Collections.singletonList(spreadArgs), false); + statements = Collections.singletonList(new ExpressionStatement(classLineNumber, classToken, ctorFinish, superCall)); + parameters = Collections.singletonList(argsIdent); + } else { + statements = Collections.emptyList(); + parameters = Collections.emptyList(); + } + + final Block body = new Block(classToken, ctorFinish, Block.IS_BODY, statements); + final IdentNode ctorName = className != null ? className : createIdentNode(identToken, ctorFinish, "constructor"); + final ParserContextFunctionNode function = createParserContextFunctionNode(ctorName, classToken, FunctionNode.Kind.NORMAL, classLineNumber, parameters); + function.setLastToken(lastToken); + + function.setFlag(FunctionNode.ES6_IS_METHOD); + function.setFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR); + if (subclass) { + function.setFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR); + function.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER); + } + if (className == null) { + function.setFlag(FunctionNode.IS_ANONYMOUS); + } + + final PropertyNode constructor = new PropertyNode(classToken, ctorFinish, ctorName, createFunctionNode( + function, + classToken, + ctorName, + parameters, + FunctionNode.Kind.NORMAL, + classLineNumber, + body + ), null, null, false, false); + return constructor; + } + + private PropertyNode methodDefinition(final boolean isStatic, final boolean subclass, final boolean generator) { + final long methodToken = token; + final int methodLine = line; + final boolean computed = type == LBRACKET; + final boolean isIdent = type == IDENT; + final Expression propertyName = propertyName(); + int flags = FunctionNode.ES6_IS_METHOD; + if (!computed) { + final String name = ((PropertyKey)propertyName).getPropertyName(); + if (!generator && isIdent && type != LPAREN && name.equals("get")) { + final PropertyFunction methodDefinition = propertyGetterFunction(methodToken, methodLine, flags); + verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true); + return new PropertyNode(methodToken, finish, methodDefinition.key, null, methodDefinition.functionNode, null, isStatic, methodDefinition.computed); + } else if (!generator && isIdent && type != LPAREN && name.equals("set")) { + final PropertyFunction methodDefinition = propertySetterFunction(methodToken, methodLine, flags); + verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true); + return new PropertyNode(methodToken, finish, methodDefinition.key, null, null, methodDefinition.functionNode, isStatic, methodDefinition.computed); + } else { + if (!isStatic && !generator && name.equals("constructor")) { + flags |= FunctionNode.ES6_IS_CLASS_CONSTRUCTOR; + if (subclass) { + flags |= FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR; + } + } + verifyAllowedMethodName(propertyName, isStatic, computed, generator, false); + } + } + final PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, flags, computed); + return new PropertyNode(methodToken, finish, methodDefinition.key, methodDefinition.functionNode, null, null, isStatic, computed); + } + + /** + * ES6 14.5.1 Static Semantics: Early Errors. + */ + private void verifyAllowedMethodName(final Expression key, final boolean isStatic, final boolean computed, final boolean generator, final boolean accessor) { + if (!computed) { + if (!isStatic && generator && ((PropertyKey) key).getPropertyName().equals("constructor")) { + throw error(AbstractParser.message("generator.constructor"), key.getToken()); + } + if (!isStatic && accessor && ((PropertyKey) key).getPropertyName().equals("constructor")) { + throw error(AbstractParser.message("accessor.constructor"), key.getToken()); + } + if (isStatic && ((PropertyKey) key).getPropertyName().equals("prototype")) { + throw error(AbstractParser.message("static.prototype.method"), key.getToken()); + } + } + } + /** * block : * { StatementList? } @@ -1008,7 +1504,7 @@ loop: */ private void statementList() { // Accumulate statements until end of list. */ -loop: + loop: while (type != EOF) { switch (type) { case EOF: @@ -1025,6 +1521,22 @@ loop: } } + /** + * Make sure that the identifier name used is allowed. + * + * @param ident Identifier that is verified + * @param contextString String used in error message to give context to the user + */ + private void verifyIdent(final IdentNode ident, final String contextString) { + verifyStrictIdent(ident, contextString); + if (isES6()) { + final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length()); + if (tokenType != IDENT && tokenType.getKind() != TokenKind.FUTURESTRICT) { + throw error(expectMessage(IDENT)); + } + } + } + /** * Make sure that in strict mode, the identifier name used is allowed. * @@ -1066,15 +1578,16 @@ loop: * Parse a VAR statement. * @param isStatement True if a statement (not used in a FOR.) */ - private List variableStatement(final TokenType varType) { - return variableStatement(varType, true, -1); + private void variableStatement(final TokenType varType) { + variableDeclarationList(varType, true, -1); } - private List variableStatement(final TokenType varType, final boolean isStatement, final int sourceOrder) { + private List variableDeclarationList(final TokenType varType, final boolean isStatement, final int sourceOrder) { // VAR tested in caller. + assert varType == VAR || varType == LET || varType == CONST; next(); - final List vars = new ArrayList<>(); + final List bindings = new ArrayList<>(); int varFlags = 0; if (varType == LET) { varFlags |= VarNode.IS_LET; @@ -1082,13 +1595,29 @@ loop: varFlags |= VarNode.IS_CONST; } + Expression missingAssignment = null; while (true) { // Get starting token. final int varLine = line; final long varToken = token; // Get name of var. - final IdentNode name = getIdent(); - verifyStrictIdent(name, "variable name"); + if (type == YIELD && inGeneratorFunction()) { + expect(IDENT); + } + + final String contextString = "variable name"; + Expression binding = bindingIdentifierOrPattern(contextString); + final boolean isDestructuring = !(binding instanceof IdentNode); + if (isDestructuring) { + final int finalVarFlags = varFlags; + verifyDestructuringBindingPattern(binding, new Consumer() { + public void accept(final IdentNode identNode) { + verifyIdent(identNode, contextString); + final VarNode var = new VarNode(varLine, varToken, sourceOrder, identNode.getFinish(), identNode.setIsDeclaredHere(), null, finalVarFlags); + appendStatement(var); + } + }); + } // Assume no init. Expression init = null; @@ -1098,22 +1627,53 @@ loop: next(); // Get initializer expression. Suppress IN if not statement. - defaultNames.push(name); + if (!isDestructuring) { + defaultNames.push(binding); + } try { init = assignmentExpression(!isStatement); } finally { - defaultNames.pop(); + if (!isDestructuring) { + defaultNames.pop(); + } } - } else if (varType == CONST && isStatement) { - throw error(AbstractParser.message("missing.const.assignment", name.getName())); + } else if (isStatement) { + if (isDestructuring) { + throw error(AbstractParser.message("missing.destructuring.assignment"), token); + } else if (varType == CONST) { + throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)binding).getName())); + } + // else, if we are in a for loop, delay checking until we know the kind of loop } - // Only set declaration flag on lexically scoped let/const as it adds runtime overhead. - final IdentNode actualName = varType == LET || varType == CONST ? name.setIsDeclaredHere() : name; - // Allocate var node. - final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, actualName, init, varFlags); - vars.add(var); - appendStatement(var); + if (!isDestructuring) { + assert init != null || varType != CONST || !isStatement; + final IdentNode ident = (IdentNode)binding; + if (!isStatement && ident.getName().equals("let")) { + throw error(AbstractParser.message("let.binding.for")); //ES6 13.7.5.1 + } + // Only set declaration flag on lexically scoped let/const as it adds runtime overhead. + final IdentNode name = varType == LET || varType == CONST ? ident.setIsDeclaredHere() : ident; + binding = name; + final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, name, init, varFlags); + appendStatement(var); + if (init == null && varType == CONST) { + if (missingAssignment == null) { + missingAssignment = binding; + } + } + } else { + assert init != null || !isStatement; + binding = init == null ? binding : verifyAssignment(Token.recast(varToken, ASSIGN), binding, init); + if (isStatement) { + appendStatement(new ExpressionStatement(varLine, binding.getToken(), finish, binding)); + } else if (init == null) { + if (missingAssignment == null) { + missingAssignment = binding; + } + } + } + bindings.add(binding); if (type != COMMARIGHT) { break; @@ -1124,9 +1684,128 @@ loop: // If is a statement then handle end of line. if (isStatement) { endOfLine(); + } else { + if (type == SEMICOLON) { + // late check for missing assignment, now we know it's a for (init; test; modify) loop + if (missingAssignment != null) { + if (missingAssignment instanceof IdentNode) { + throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)missingAssignment).getName())); + } else { + throw error(AbstractParser.message("missing.destructuring.assignment"), missingAssignment.getToken()); + } + } + } } - return vars; + return bindings; + } + + private boolean isBindingIdentifier() { + return type == IDENT || isNonStrictModeIdent(); + } + + private IdentNode bindingIdentifier(final String contextString) { + final IdentNode name = getIdent(); + verifyIdent(name, contextString); + return name; + } + + private Expression bindingPattern() { + if (type == LBRACKET) { + return arrayLiteral(); + } else if (type == LBRACE) { + return objectLiteral(); + } else { + throw error(AbstractParser.message("expected.binding")); + } + } + + private Expression bindingIdentifierOrPattern(final String contextString) { + if (isBindingIdentifier() || !isES6()) { + return bindingIdentifier(contextString); + } else { + return bindingPattern(); + } + } + + /** + * Verify destructuring variable declaration binding pattern and extract bound variable declarations. + */ + private void verifyDestructuringBindingPattern(final Expression pattern, final Consumer identifierCallback) { + assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode; + pattern.accept(new NodeVisitor(new LexicalContext()) { + @Override + public boolean enterLiteralNode(final LiteralNode literalNode) { + if (literalNode.isArray()) { + boolean restElement = false; + for (final Expression element : literalNode.getElementExpressions()) { + if (restElement) { + throw error(String.format("Unexpected element after rest element"), element.getToken()); + } + if (element != null) { + if (element.isTokenType(SPREAD_ARRAY)) { + restElement = true; + if (!(((UnaryNode) element).getExpression() instanceof IdentNode)) { + throw error(String.format("Expected a valid binding identifier"), element.getToken()); + + } + } + element.accept(this); + } + } + return false; + } else { + return enterDefault(literalNode); + } + } + + @Override + public boolean enterObjectNode(final ObjectNode objectNode) { + return true; + } + + @Override + public boolean enterPropertyNode(final PropertyNode propertyNode) { + if (propertyNode.getValue() != null) { + propertyNode.getValue().accept(this); + return false; + } else { + return enterDefault(propertyNode); + } + } + + @Override + public boolean enterIdentNode(final IdentNode identNode) { + identifierCallback.accept(identNode); + return false; + } + + @Override + public boolean enterBinaryNode(final BinaryNode binaryNode) { + if (binaryNode.isTokenType(ASSIGN)) { + binaryNode.lhs().accept(this); + // Initializer(rhs) can be any AssignmentExpression + return false; + } else { + return enterDefault(binaryNode); + } + } + + @Override + public boolean enterUnaryNode(final UnaryNode unaryNode) { + if (unaryNode.isTokenType(SPREAD_ARRAY)) { + // rest element + return true; + } else { + return enterDefault(unaryNode); + } + } + + @Override + protected boolean enterDefault(final Node node) { + throw error(String.format("unexpected node in BindingPattern: %s", node)); + } + }); } /** @@ -1230,7 +1909,7 @@ loop: final ParserContextLoopNode forNode = new ParserContextLoopNode(); lc.push(forNode); Block body = null; - List vars = null; + List vars = null; Expression init = null; JoinPredecessorExpression test = null; JoinPredecessorExpression modify = null; @@ -1254,20 +1933,20 @@ loop: switch (type) { case VAR: // Var declaration captured in for outer block. - vars = variableStatement(type, false, forStart); + vars = variableDeclarationList(type, false, forStart); break; case SEMICOLON: break; default: - if (useBlockScope() && (type == LET || type == CONST)) { + if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(true) || type == CONST)) { flags |= ForNode.PER_ITERATION_SCOPE; // LET/CONST declaration captured in container block created above. - vars = variableStatement(type, false, forStart); + vars = variableDeclarationList(type, false, forStart); break; } if (env._const_as_var && type == CONST) { // Var declaration captured in for outer block. - vars = variableStatement(TokenType.VAR, false, forStart); + vars = variableDeclarationList(TokenType.VAR, false, forStart); break; } @@ -1309,7 +1988,11 @@ loop: if (vars != null) { // for (var i in obj) if (vars.size() == 1) { - init = new IdentNode(vars.get(0).getName()); + init = new IdentNode((IdentNode)vars.get(0)); + if (init.isTokenType(ASSIGN)) { + throw error(AbstractParser.message("for.in.loop.initializer"), init.getToken()); + } + assert init instanceof IdentNode || isDestructuringLhs(init); } else { // for (var i, j in obj) is invalid throw error(AbstractParser.message("many.vars.in.for.in.loop", isForOf ? "of" : "in"), vars.get(1).getToken()); @@ -1351,10 +2034,9 @@ loop: } finally { lc.pop(forNode); - if (vars != null) { - for (final VarNode var : vars) { - appendStatement(var); - } + for (final Statement var : forNode.getStatements()) { + assert var instanceof VarNode; + appendStatement(var); } if (body != null) { appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify)); @@ -1371,6 +2053,49 @@ loop: } } + private boolean checkValidLValue(final Expression init, final String contextString) { + if (init instanceof IdentNode) { + if (!checkIdentLValue((IdentNode)init)) { + return false; + } + verifyIdent((IdentNode)init, contextString); + return true; + } else if (init instanceof AccessNode || init instanceof IndexNode) { + return true; + } else if (isDestructuringLhs(init)) { + verifyDestructuringAssignmentPattern(init, contextString); + return true; + } else { + return false; + } + } + + private boolean lookaheadIsLetDeclaration(final boolean ofContextualKeyword) { + assert type == LET; + for (int i = 1;; i++) { + TokenType t = T(k + i); + switch (t) { + case EOL: + case COMMENT: + continue; + case IDENT: + if (ofContextualKeyword && isES6() && "of".equals(getValue(getToken(k + i)))) { + return false; + } + // fall through + case LBRACKET: + case LBRACE: + return true; + default: + // accept future strict tokens in non-strict mode (including LET) + if (!isStrictMode && t.getKind() == TokenKind.FUTURESTRICT) { + return true; + } + return false; + } + } + } + /** * ...IterationStatement : * ... @@ -1559,7 +2284,7 @@ loop: */ private void returnStatement() { // check for return outside function - if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) { + if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT || lc.getCurrentFunction().getKind() == FunctionNode.Kind.MODULE) { throw error(AbstractParser.message("invalid.return")); } @@ -1591,39 +2316,61 @@ loop: } /** - * YieldStatement : - * yield Expression? ; // [no LineTerminator here] + * Parse YieldExpression. * - * JavaScript 1.8 - * - * Parse YIELD statement. + * YieldExpression[In] : + * yield + * yield [no LineTerminator here] AssignmentExpression[?In, Yield] + * yield [no LineTerminator here] * AssignmentExpression[?In, Yield] */ - private void yieldStatement() { + private Expression yieldExpression(final boolean noIn) { + assert inGeneratorFunction(); // Capture YIELD token. - final int yieldLine = line; - final long yieldToken = token; + long yieldToken = token; // YIELD tested in caller. + assert type == YIELD; nextOrEOL(); Expression expression = null; - // SEMICOLON or expression. + boolean yieldAsterisk = false; + if (type == MUL) { + yieldAsterisk = true; + yieldToken = Token.recast(yieldToken, YIELD_STAR); + next(); + } + switch (type) { case RBRACE: case SEMICOLON: case EOL: case EOF: - break; + case COMMARIGHT: + case RPAREN: + case RBRACKET: + case COLON: + if (!yieldAsterisk) { + // treat (yield) as (yield void 0) + expression = newUndefinedLiteral(yieldToken, finish); + if (type == EOL) { + next(); + } + break; + } else { + // AssignmentExpression required, fall through + } default: - expression = expression(); + expression = assignmentExpression(noIn); break; } - endOfLine(); - // Construct and add YIELD node. - appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression)); + return new UnaryNode(yieldToken, expression); + } + + private static UnaryNode newUndefinedLiteral(final long token, final int finish) { + return new UnaryNode(Token.recast(token, VOID), LiteralNode.newInstance(token, finish, 0)); } /** @@ -1679,11 +2426,15 @@ loop: private void switchStatement() { final int switchLine = line; final long switchToken = token; + + // Block to capture variables declared inside the switch statement. + final ParserContextBlockNode switchBlock = newBlock(); + // SWITCH tested in caller. next(); // Create and add switch statement. - final ParserContextSwitchNode switchNode= new ParserContextSwitchNode(); + final ParserContextSwitchNode switchNode = new ParserContextSwitchNode(); lc.push(switchNode); CaseNode defaultCase = null; @@ -1727,7 +2478,7 @@ loop: expect(COLON); // Get CASE body. - final Block statements = getBlock(false); + final Block statements = getBlock(false); // TODO: List statements = caseStatementList(); final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements); if (caseExpression == null) { @@ -1740,9 +2491,11 @@ loop: next(); } finally { lc.pop(switchNode); + restoreBlock(switchBlock); } - appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase)); + final SwitchNode switchStatement = new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase); + appendStatement(new BlockStatement(switchLine, new Block(switchToken, finish, switchBlock.getFlags() | Block.IS_SYNTHETIC | Block.IS_SWITCH_BLOCK, switchStatement))); } /** @@ -1769,7 +2522,7 @@ loop: Block body = null; try { lc.push(labelNode); - body = getStatement(); + body = getStatement(true); } finally { assert lc.peek() instanceof ParserContextLabelNode; lc.pop(labelNode); @@ -1935,13 +2688,19 @@ loop: /** * PrimaryExpression : * this - * Identifier + * IdentifierReference * Literal * ArrayLiteral * ObjectLiteral * RegularExpressionLiteral * TemplateLiteral + * CoverParenthesizedExpressionAndArrowParameterList + * + * CoverParenthesizedExpressionAndArrowParameterList : * ( Expression ) + * ( ) + * ( ... BindingIdentifier ) + * ( Expression , ... BindingIdentifier ) * * Parse primary expression. * @return Expression node. @@ -1956,7 +2715,7 @@ loop: case THIS: final String name = type.getName(); next(); - lc.getCurrentFunction().setFlag(FunctionNode.USES_THIS); + markThis(lc); return new IdentNode(primaryToken, finish, name); case IDENT: final IdentNode ident = getIdent(); @@ -1997,6 +2756,22 @@ loop: case LPAREN: next(); + if (isES6()) { + if (type == RPAREN) { + // () + nextOrEOL(); + expectDontAdvance(ARROW); + return new ExpressionList(primaryToken, finish, Collections.emptyList()); + } else if (type == ELLIPSIS) { + // (...rest) + final IdentNode restParam = formalParameterList(false).get(0); + expectDontAdvance(RPAREN); + nextOrEOL(); + expectDontAdvance(ARROW); + return new ExpressionList(primaryToken, finish, Collections.singletonList(restParam)); + } + } + final Expression expression = expression(); expect(RPAREN); @@ -2073,8 +2848,9 @@ loop: final List elements = new ArrayList<>(); // Track elisions. boolean elision = true; -loop: + loop: while (true) { + long spreadToken = 0; switch (type) { case RBRACKET: next(); @@ -2093,14 +2869,24 @@ loop: break; + case ELLIPSIS: + if (isES6()) { + spreadToken = token; + next(); + } + // fall through + default: if (!elision) { throw error(AbstractParser.message("expected.comma", type.getNameOrType())); } - // Add expression element. - final Expression expression = assignmentExpression(false); + // Add expression element. + Expression expression = assignmentExpression(false); if (expression != null) { + if (spreadToken != 0) { + expression = new UnaryNode(Token.recast(spreadToken, SPREAD_ARRAY), expression); + } elements.add(expression); } else { expect(RBRACKET); @@ -2141,7 +2927,7 @@ loop: // Create a block for the object literal. boolean commaSeen = true; -loop: + loop: while (true) { switch (type) { case RBRACE: @@ -2164,6 +2950,12 @@ loop: commaSeen = false; // Get and add the next property. final PropertyNode property = propertyAssignment(); + + if (property.isComputed()) { + elements.add(property); + break; + } + final String key = property.getKeyName(); final Integer existing = map.get(key); @@ -2185,36 +2977,23 @@ loop: final FunctionNode prevGetter = existingProperty.getGetter(); final FunctionNode prevSetter = existingProperty.getSetter(); - // ECMA 11.1.5 strict mode restrictions - if (isStrictMode && value != null && prevValue != null) { - throw error(AbstractParser.message("property.redefinition", key), property.getToken()); - } - - final boolean isPrevAccessor = prevGetter != null || prevSetter != null; - final boolean isAccessor = getter != null || setter != null; - - // data property redefined as accessor property - if (prevValue != null && isAccessor) { - throw error(AbstractParser.message("property.redefinition", key), property.getToken()); - } - - // accessor property redefined as data - if (isPrevAccessor && value != null) { - throw error(AbstractParser.message("property.redefinition", key), property.getToken()); - } - - if (isAccessor && isPrevAccessor) { - if (getter != null && prevGetter != null || - setter != null && prevSetter != null) { - throw error(AbstractParser.message("property.redefinition", key), property.getToken()); + if (!isES6()) { + checkPropertyRedefinition(property, value, getter, setter, prevValue, prevGetter, prevSetter); + } else { + if (property.getKey() instanceof IdentNode && ((IdentNode)property.getKey()).isProtoPropertyName() && + existingProperty.getKey() instanceof IdentNode && ((IdentNode)existingProperty.getKey()).isProtoPropertyName()) { + throw error(AbstractParser.message("multiple.proto.key"), property.getToken()); } } - if (value != null) { + if (value != null || prevValue != null) { + map.put(key, elements.size()); elements.add(property); } else if (getter != null) { + assert prevGetter != null || prevSetter != null; elements.set(existing, existingProperty.setGetter(getter)); } else if (setter != null) { + assert prevGetter != null || prevSetter != null; elements.set(existing, existingProperty.setSetter(setter)); } break; @@ -2224,18 +3003,43 @@ loop: return new ObjectNode(objectToken, finish, elements); } + private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) { + // ECMA 11.1.5 strict mode restrictions + if (isStrictMode && value != null && prevValue != null) { + throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); + } + + final boolean isPrevAccessor = prevGetter != null || prevSetter != null; + final boolean isAccessor = getter != null || setter != null; + + // data property redefined as accessor property + if (prevValue != null && isAccessor) { + throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); + } + + // accessor property redefined as data + if (isPrevAccessor && value != null) { + throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); + } + + if (isAccessor && isPrevAccessor) { + if (getter != null && prevGetter != null || + setter != null && prevSetter != null) { + throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); + } + } + } + /** - * PropertyName : + * LiteralPropertyName : * IdentifierName * StringLiteral * NumericLiteral * - * See 11.1.5 - * * @return PropertyName node */ @SuppressWarnings("fallthrough") - private PropertyKey propertyName() { + private PropertyKey literalPropertyName() { switch (type) { case IDENT: return getIdent().setIsPropertyName(); @@ -2256,6 +3060,34 @@ loop: } } + /** + * ComputedPropertyName : + * AssignmentExpression + * + * @return PropertyName node + */ + private Expression computedPropertyName() { + expect(LBRACKET); + Expression expression = assignmentExpression(false); + expect(RBRACKET); + return expression; + } + + /** + * PropertyName : + * LiteralPropertyName + * ComputedPropertyName + * + * @return PropertyName node + */ + private Expression propertyName() { + if (type == LBRACKET && isES6()) { + return computedPropertyName(); + } else { + return (Expression)literalPropertyName(); + } + } + /** * PropertyAssignment : * PropertyName : AssignmentExpression @@ -2280,51 +3112,95 @@ loop: final long propertyToken = token; final int functionLine = line; - PropertyKey propertyName; + final Expression propertyName; + final boolean isIdentifier; + boolean generator = false; + if (type == MUL && isES6()) { + generator = true; + next(); + } + + final boolean computed = type == LBRACKET; if (type == IDENT) { // Get IDENT. final String ident = (String)expectValue(IDENT); - if (type != COLON) { + if (type != COLON && (type != LPAREN || !isES6())) { final long getSetToken = propertyToken; switch (ident) { case "get": final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); - return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null); + return new PropertyNode(propertyToken, finish, getter.key, null, getter.functionNode, null, false, getter.computed); case "set": final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); - return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode); + return new PropertyNode(propertyToken, finish, setter.key, null, null, setter.functionNode, false, setter.computed); default: break; } } - propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); + isIdentifier = true; + IdentNode identNode = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); + if (type == COLON && ident.equals("__proto__")) { + identNode = identNode.setIsProtoPropertyName(); + } + propertyName = identNode; } else { + isIdentifier = isNonStrictModeIdent(); propertyName = propertyName(); } - expect(COLON); + Expression propertyValue; - defaultNames.push(propertyName); - try { - return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); - } finally { - defaultNames.pop(); + if (generator) { + expectDontAdvance(LPAREN); } + + if (type == LPAREN && isES6()) { + propertyValue = propertyMethodFunction(propertyName, propertyToken, functionLine, generator, FunctionNode.ES6_IS_METHOD, computed).functionNode; + } else if (isIdentifier && (type == COMMARIGHT || type == RBRACE || type == ASSIGN) && isES6()) { + propertyValue = createIdentNode(propertyToken, finish, ((IdentNode) propertyName).getPropertyName()); + if (type == ASSIGN && isES6()) { + // TODO if not destructuring, this is a SyntaxError + final long assignToken = token; + next(); + final Expression rhs = assignmentExpression(false); + propertyValue = verifyAssignment(assignToken, propertyValue, rhs); + } + } else { + expect(COLON); + + defaultNames.push(propertyName); + try { + propertyValue = assignmentExpression(false); + } finally { + defaultNames.pop(); + } + } + + return new PropertyNode(propertyToken, finish, propertyName, propertyValue, null, null, false, computed); } private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { - final PropertyKey getIdent = propertyName(); - final String getterName = getIdent.getPropertyName(); - final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName)); + return propertyGetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD); + } + + private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine, final int flags) { + final boolean computed = type == LBRACKET; + final Expression propertyName = propertyName(); + final String getterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false); + final IdentNode getNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("get " + getterName)); expect(LPAREN); expect(RPAREN); final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.emptyList()); + functionNode.setFlag(flags); + if (computed) { + functionNode.setFlag(FunctionNode.IS_ANONYMOUS); + } lc.push(functionNode); Block functionBody; @@ -2345,20 +3221,25 @@ loop: functionLine, functionBody); - return new PropertyFunction(getIdent, function); + return new PropertyFunction(propertyName, function, computed); } private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) { - final PropertyKey setIdent = propertyName(); - final String setterName = setIdent.getPropertyName(); - final IdentNode setNameNode = createIdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName)); + return propertySetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD); + } + + private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine, final int flags) { + final boolean computed = type == LBRACKET; + final Expression propertyName = propertyName(); + final String setterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false); + final IdentNode setNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("set " + setterName)); expect(LPAREN); // be sloppy and allow missing setter parameter even though // spec does not permit it! final IdentNode argIdent; - if (type == IDENT || isNonStrictModeIdent()) { + if (isBindingIdentifier()) { argIdent = getIdent(); - verifyStrictIdent(argIdent, "setter argument"); + verifyIdent(argIdent, "setter argument"); } else { argIdent = null; } @@ -2370,6 +3251,10 @@ loop: final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters); + functionNode.setFlag(flags); + if (computed) { + functionNode.setFlag(FunctionNode.IS_ANONYMOUS); + } lc.push(functionNode); Block functionBody; @@ -2389,33 +3274,81 @@ loop: functionLine, functionBody); - return new PropertyFunction(setIdent, function); + return new PropertyFunction(propertyName, function, computed); + } + + private PropertyFunction propertyMethodFunction(Expression key, final long methodToken, final int methodLine, final boolean generator, final int flags, boolean computed) { + final String methodName = key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : getDefaultValidFunctionName(methodLine, false); + final IdentNode methodNameNode = createIdentNode(((Node)key).getToken(), finish, methodName); + + FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL; + final ParserContextFunctionNode functionNode = createParserContextFunctionNode(methodNameNode, methodToken, functionKind, methodLine, null); + functionNode.setFlag(flags); + if (computed) { + functionNode.setFlag(FunctionNode.IS_ANONYMOUS); + } + lc.push(functionNode); + + try { + final ParserContextBlockNode parameterBlock = newBlock(); + final List parameters; + try { + expect(LPAREN); + parameters = formalParameterList(generator); + functionNode.setParameters(parameters); + expect(RPAREN); + } finally { + restoreBlock(parameterBlock); + } + + Block functionBody = functionBody(functionNode); + + functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); + + final FunctionNode function = createFunctionNode( + functionNode, + methodToken, + methodNameNode, + parameters, + functionKind, + methodLine, + functionBody); + return new PropertyFunction(key, function, computed); + } finally { + lc.pop(functionNode); + } } private static class PropertyFunction { - final PropertyKey ident; + final Expression key; final FunctionNode functionNode; + final boolean computed; - PropertyFunction(final PropertyKey ident, final FunctionNode function) { - this.ident = ident; + PropertyFunction(final Expression key, final FunctionNode function, final boolean computed) { + this.key = key; this.functionNode = function; + this.computed = computed; } } /** - * Parse left hand side expression. - * * LeftHandSideExpression : * NewExpression * CallExpression * * CallExpression : * MemberExpression Arguments + * SuperCall * CallExpression Arguments * CallExpression [ Expression ] * CallExpression . IdentifierName - * CallExpression TemplateLiteral * + * SuperCall : + * super Arguments + * + * See 11.2 + * + * Parse left hand side expression. * @return Expression node. */ private Expression leftHandSideExpression() { @@ -2435,7 +3368,7 @@ loop: lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); } -loop: + loop: while (true) { // Capture token. callLine = line; @@ -2479,6 +3412,7 @@ loop: // tagged template literal final List arguments = templateLiteralArgumentList(); + // Create call node. lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); break; @@ -2506,6 +3440,20 @@ loop: // NEW is tested in caller. next(); + if (type == PERIOD && isES6()) { + next(); + if (type == IDENT && "target".equals(getValue())) { + if (lc.getCurrentFunction().isProgram()) { + throw error(AbstractParser.message("new.target.in.function"), token); + } + next(); + markNewTarget(lc); + return new IdentNode(newToken, finish, "new.target"); + } else { + throw error(AbstractParser.message("expected.target"), token); + } + } + // Get function base. final int callLine = line; final Expression constructor = memberExpression(); @@ -2541,21 +3489,33 @@ loop: } /** - * Parse member expression. - * * MemberExpression : * PrimaryExpression - * FunctionExpression + * FunctionExpression + * ClassExpression + * GeneratorExpression * MemberExpression [ Expression ] * MemberExpression . IdentifierName * MemberExpression TemplateLiteral + * SuperProperty + * MetaProperty * new MemberExpression Arguments * + * SuperProperty : + * super [ Expression ] + * super . IdentifierName + * + * MetaProperty : + * NewTarget + * + * Parse member expression. * @return Expression node. */ + @SuppressWarnings("fallthrough") private Expression memberExpression() { // Prepare to build operation. Expression lhs; + boolean isSuper = false; switch (type) { case NEW: @@ -2568,13 +3528,53 @@ loop: lhs = functionExpression(false, false); break; + case CLASS: + if (isES6()) { + lhs = classExpression(false); + break; + } else { + // fall through + } + + case SUPER: + if (isES6()) { + final ParserContextFunctionNode currentFunction = getCurrentNonArrowFunction(); + if (currentFunction.isMethod()) { + long identToken = Token.recast(token, IDENT); + next(); + lhs = createIdentNode(identToken, finish, SUPER.getName()); + + switch (type) { + case LBRACKET: + case PERIOD: + getCurrentNonArrowFunction().setFlag(FunctionNode.ES6_USES_SUPER); + isSuper = true; + break; + case LPAREN: + if (currentFunction.isSubclassConstructor()) { + lhs = ((IdentNode)lhs).setIsDirectSuper(); + break; + } else { + // fall through to throw error + } + default: + throw error(AbstractParser.message("invalid.super"), identToken); + } + break; + } else { + // fall through + } + } else { + // fall through + } + default: // Get primary expression. lhs = primaryExpression(); break; } -loop: + loop: while (true) { // Capture token. final long callToken = token; @@ -2591,6 +3591,11 @@ loop: // Create indexing node. lhs = new IndexNode(callToken, finish, lhs, index); + if (isSuper) { + isSuper = false; + lhs = ((BaseNode) lhs).setIsSuper(); + } + break; } case PERIOD: { @@ -2605,6 +3610,11 @@ loop: // Create property access node. lhs = new AccessNode(callToken, finish, lhs, property.getName()); + if (isSuper) { + isSuper = false; + lhs = ((BaseNode) lhs).setIsSuper(); + } + break; } case TEMPLATE: @@ -2632,7 +3642,9 @@ loop: * * ArgumentList : * AssignmentExpression + * ... AssignmentExpression * ArgumentList , AssignmentExpression + * ArgumentList , ... AssignmentExpression * * See 11.2 * @@ -2656,8 +3668,18 @@ loop: first = false; } + long spreadToken = 0; + if (type == ELLIPSIS && isES6()) { + spreadToken = token; + next(); + } + // Get argument expression. - nodeList.add(assignmentExpression(false)); + Expression expression = assignmentExpression(false); + if (spreadToken != 0) { + expression = new UnaryNode(Token.recast(spreadToken, TokenType.SPREAD_ARGUMENT), expression); + } + nodeList.add(expression); } expect(RPAREN); @@ -2697,11 +3719,24 @@ loop: final long functionToken = token; final int functionLine = line; // FUNCTION is tested in caller. + assert type == FUNCTION; next(); + boolean generator = false; + if (type == MUL && isES6()) { + generator = true; + next(); + } + IdentNode name = null; - if (type == IDENT || isNonStrictModeIdent()) { + if (isBindingIdentifier()) { + if (type == YIELD && ((!isStatement && generator) || (isStatement && inGeneratorFunction()))) { + // 12.1.1 Early SyntaxError if: + // GeneratorExpression with BindingIdentifier yield + // HoistableDeclaration with BindingIdentifier yield in generator function body + expect(IDENT); + } name = getIdent(); verifyStrictIdent(name, "function name"); } else if (isStatement) { @@ -2723,25 +3758,36 @@ loop: isAnonymous = true; } - expect(LPAREN); - final List parameters = formalParameterList(); - expect(RPAREN); - - final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters); + FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL; + List parameters = Collections.emptyList(); + final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, functionKind, functionLine, parameters); lc.push(functionNode); + Block functionBody = null; // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}" // If we didn't hide the current default name, then the innermost anonymous function would receive "x3". hideDefaultName(); - try{ + try { + final ParserContextBlockNode parameterBlock = newBlock(); + try { + expect(LPAREN); + parameters = formalParameterList(generator); + functionNode.setParameters(parameters); + expect(RPAREN); + } finally { + restoreBlock(parameterBlock); + } + functionBody = functionBody(functionNode); + + functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); } finally { defaultNames.pop(); lc.pop(functionNode); } if (isStatement) { - if (topLevel || useBlockScope()) { + if (topLevel || useBlockScope() || (!isStrictMode && env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ACCEPT)) { functionNode.setFlag(FunctionNode.IS_DECLARED); } else if (isStrictMode) { throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); @@ -2759,45 +3805,14 @@ loop: functionNode.setFlag(FunctionNode.IS_ANONYMOUS); } - final int arity = parameters.size(); - - final boolean strict = functionNode.isStrict(); - if (arity > 1) { - final HashSet parametersSet = new HashSet<>(arity); - - for (int i = arity - 1; i >= 0; i--) { - final IdentNode parameter = parameters.get(i); - String parameterName = parameter.getName(); - - if (isArguments(parameterName)) { - functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); - } - - if (parametersSet.contains(parameterName)) { - // redefinition of parameter name - if (strict) { - throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); - } - // rename in non-strict mode - parameterName = functionNode.uniqueName(parameterName); - final long parameterToken = parameter.getToken(); - parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); - } - - parametersSet.add(parameterName); - } - } else if (arity == 1) { - if (isArguments(parameters.get(0))) { - functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); - } - } + verifyParameterList(parameters, functionNode); final FunctionNode function = createFunctionNode( functionNode, functionToken, name, parameters, - FunctionNode.Kind.NORMAL, + functionKind, functionLine, functionBody); @@ -2822,6 +3837,40 @@ loop: return function; } + private void verifyParameterList(final List parameters, final ParserContextFunctionNode functionNode) { + final IdentNode duplicateParameter = functionNode.getDuplicateParameterBinding(); + if (duplicateParameter != null) { + if (functionNode.isStrict() || functionNode.getKind() == FunctionNode.Kind.ARROW || !functionNode.isSimpleParameterList()) { + throw error(AbstractParser.message("strict.param.redefinition", duplicateParameter.getName()), duplicateParameter.getToken()); + } + + final int arity = parameters.size(); + final HashSet parametersSet = new HashSet<>(arity); + + for (int i = arity - 1; i >= 0; i--) { + final IdentNode parameter = parameters.get(i); + String parameterName = parameter.getName(); + + if (parametersSet.contains(parameterName)) { + // redefinition of parameter name, rename in non-strict mode + parameterName = functionNode.uniqueName(parameterName); + final long parameterToken = parameter.getToken(); + parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); + } + parametersSet.add(parameterName); + } + } + } + + private static Block maybeWrapBodyInParameterBlock(Block functionBody, ParserContextBlockNode parameterBlock) { + assert functionBody.isFunctionBody(); + if (!parameterBlock.getStatements().isEmpty()) { + parameterBlock.appendStatement(new BlockStatement(functionBody)); + return new Block(parameterBlock.getToken(), functionBody.getFinish(), (functionBody.getFlags() | Block.IS_PARAMETER_BLOCK) & ~Block.IS_BODY, parameterBlock.getStatements()); + } + return functionBody; + } + private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) { final String defaultFunctionName = getDefaultFunctionName(); if (isValidIdentifier(defaultFunctionName)) { @@ -2836,14 +3885,14 @@ loop: } private static boolean isValidIdentifier(final String name) { - if(name == null || name.isEmpty()) { + if (name == null || name.isEmpty()) { return false; } - if(!Character.isJavaIdentifierStart(name.charAt(0))) { + if (!Character.isJavaIdentifierStart(name.charAt(0))) { return false; } - for(int i = 1; i < name.length(); ++i) { - if(!Character.isJavaIdentifierPart(name.charAt(i))) { + for (int i = 1; i < name.length(); ++i) { + if (!Character.isJavaIdentifierPart(name.charAt(i))) { return false; } } @@ -2851,12 +3900,12 @@ loop: } private String getDefaultFunctionName() { - if(!defaultNames.isEmpty()) { + if (!defaultNames.isEmpty()) { final Object nameExpr = defaultNames.peek(); - if(nameExpr instanceof PropertyKey) { + if (nameExpr instanceof PropertyKey) { markDefaultNameUsed(); return ((PropertyKey)nameExpr).getPropertyName(); - } else if(nameExpr instanceof AccessNode) { + } else if (nameExpr instanceof AccessNode) { markDefaultNameUsed(); return ((AccessNode)nameExpr).getProperty(); } @@ -2885,8 +3934,8 @@ loop: * Parse function parameter list. * @return List of parameter nodes. */ - private List formalParameterList() { - return formalParameterList(RPAREN); + private List formalParameterList(final boolean yield) { + return formalParameterList(RPAREN, yield); } /** @@ -2902,7 +3951,7 @@ loop: * Parse function parameter list. * @return List of parameter nodes. */ - private List formalParameterList(final TokenType endType) { + private List formalParameterList(final TokenType endType, final boolean yield) { // Prepare to gather parameters. final ArrayList parameters = new ArrayList<>(); // Track commas. @@ -2916,12 +3965,84 @@ loop: first = false; } - // Get and add parameter. - final IdentNode ident = getIdent(); + boolean restParameter = false; + if (type == ELLIPSIS && isES6()) { + next(); + restParameter = true; + } - // ECMA 13.1 strict mode restrictions - verifyStrictIdent(ident, "function parameter"); + if (type == YIELD && yield) { + expect(IDENT); + } + final long paramToken = token; + final int paramLine = line; + final String contextString = "function parameter"; + IdentNode ident; + if (isBindingIdentifier() || restParameter || !isES6()) { + ident = bindingIdentifier(contextString); + + if (restParameter) { + ident = ident.setIsRestParameter(); + // rest parameter must be last + expectDontAdvance(endType); + parameters.add(ident); + break; + } else if (type == ASSIGN && isES6()) { + next(); + ident = ident.setIsDefaultParameter(); + + if (type == YIELD && yield) { + // error: yield in default expression + expect(IDENT); + } + + // default parameter + Expression initializer = assignmentExpression(false); + + ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); + if (currentFunction != null) { + // desugar to: param = (param === undefined) ? initializer : param; + // possible alternative: if (param === undefined) param = initializer; + BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); + TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); + BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value); + lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); + } + } + + ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); + if (currentFunction != null) { + currentFunction.addParameterBinding(ident); + if (ident.isRestParameter() || ident.isDefaultParameter()) { + currentFunction.setSimpleParameterList(false); + } + } + } else { + final Expression pattern = bindingPattern(); + // Introduce synthetic temporary parameter to capture the object to be destructured. + ident = createIdentNode(paramToken, pattern.getFinish(), String.format("arguments[%d]", parameters.size())).setIsDestructuredParameter(); + verifyDestructuringParameterBindingPattern(pattern, paramToken, paramLine, contextString); + + Expression value = ident; + if (type == ASSIGN) { + next(); + ident = ident.setIsDefaultParameter(); + + // binding pattern with initializer. desugar to: (param === undefined) ? initializer : param + Expression initializer = assignmentExpression(false); + // TODO initializer must not contain yield expression if yield=true (i.e. this is generator function's parameter list) + BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); + value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); + } + + ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); + if (currentFunction != null) { + // destructuring assignment + BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), pattern, value); + lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); + } + } parameters.add(ident); } @@ -2929,6 +4050,23 @@ loop: return parameters; } + private void verifyDestructuringParameterBindingPattern(final Expression pattern, final long paramToken, final int paramLine, final String contextString) { + verifyDestructuringBindingPattern(pattern, new Consumer() { + public void accept(IdentNode identNode) { + verifyIdent(identNode, contextString); + + ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); + if (currentFunction != null) { + // declare function-scope variables for destructuring bindings + lc.getFunctionBody(currentFunction).appendStatement(new VarNode(paramLine, Token.recast(paramToken, VAR), pattern.getFinish(), identNode, null)); + // detect duplicate bounds names in parameter list + currentFunction.addParameterBinding(identNode); + currentFunction.setSimpleParameterList(false); + } + } + }); + } + /** * FunctionBody : * SourceElements? @@ -2958,7 +4096,7 @@ loop: final int functionId = functionNode.getId(); parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId(); // Nashorn extension: expression closures - if (!env._no_syntax_extensions && type != LBRACE) { + if ((!env._no_syntax_extensions || functionNode.getKind() == FunctionNode.Kind.ARROW) && type != LBRACE) { /* * Example: * @@ -2967,7 +4105,7 @@ loop: */ // just expression as function body - final Expression expr = assignmentExpression(true); + final Expression expr = assignmentExpression(false); lastToken = previousToken; functionNode.setLastToken(previousToken); assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); @@ -2982,6 +4120,7 @@ loop: final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr); appendStatement(returnNode); } + // bodyFinish = finish; } else { expectDontAdvance(LBRACE); if (parseBody || !skipFunctionBody(functionNode)) { @@ -3054,7 +4193,7 @@ loop: } } } - functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements()); + functionBody = new Block(bodyToken, bodyFinish, body.getFlags() | Block.IS_BODY, body.getStatements()); return functionBody; } @@ -3095,8 +4234,7 @@ loop: // Doesn't really matter, but it's safe to treat it as if there were a semicolon before // the RBRACE. type = SEMICOLON; - k = -1; - next(); + scanFirstToken(); return true; } @@ -3126,11 +4264,11 @@ loop: } private void printAST(final FunctionNode functionNode) { - if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) { + if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) { env.getErr().println(new ASTWriter(functionNode)); } - if (functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) { + if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) { env.getErr().println(new PrintVisitor(functionNode, true, false)); } } @@ -3222,20 +4360,7 @@ loop: throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); } - if (!(lhs instanceof AccessNode || - lhs instanceof IndexNode || - lhs instanceof IdentNode)) { - return referenceError(lhs, null, env._early_lvalue_error); - } - - if (lhs instanceof IdentNode) { - if (!checkIdentLValue((IdentNode)lhs)) { - return referenceError(lhs, null, false); - } - verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); - } - - return incDecExpression(unaryToken, opType, lhs, false); + return verifyIncDecExpression(unaryToken, opType, lhs, false); default: break; @@ -3247,29 +4372,16 @@ loop: switch (type) { case INCPREFIX: case DECPREFIX: + final long opToken = token; final TokenType opType = type; final Expression lhs = expression; // ++, -- without operand.. if (lhs == null) { throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); } - - if (!(lhs instanceof AccessNode || - lhs instanceof IndexNode || - lhs instanceof IdentNode)) { - next(); - return referenceError(lhs, null, env._early_lvalue_error); - } - if (lhs instanceof IdentNode) { - if (!checkIdentLValue((IdentNode)lhs)) { - next(); - return referenceError(lhs, null, false); - } - verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); - } - expression = incDecExpression(token, type, expression, true); next(); - break; + + return verifyIncDecExpression(opToken, opType, lhs, true); default: break; } @@ -3282,6 +4394,25 @@ loop: return expression; } + private Expression verifyIncDecExpression(final long unaryToken, final TokenType opType, final Expression lhs, final boolean isPostfix) { + assert lhs != null; + + if (!(lhs instanceof AccessNode || + lhs instanceof IndexNode || + lhs instanceof IdentNode)) { + return referenceError(lhs, null, env._early_lvalue_error); + } + + if (lhs instanceof IdentNode) { + if (!checkIdentLValue((IdentNode)lhs)) { + return referenceError(lhs, null, false); + } + verifyIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); + } + + return incDecExpression(unaryToken, opType, lhs, isPostfix); + } + /** * {@code * MultiplicativeExpression : @@ -3380,7 +4511,42 @@ loop: // at expression start point! // Include commas in expression parsing. - return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false); + return expression(false); + } + + private Expression expression(final boolean noIn) { + Expression assignmentExpression = assignmentExpression(noIn); + while (type == COMMARIGHT) { + long commaToken = token; + next(); + + boolean rhsRestParameter = false; + if (type == ELLIPSIS && isES6()) { + // (a, b, ...rest) is not a valid expression, unless we're parsing the parameter list of an arrow function (we need to throw the right error). + // But since the rest parameter is always last, at least we know that the expression has to end here and be followed by RPAREN and ARROW, so peek ahead. + if (isRestParameterEndOfArrowFunctionParameterList()) { + next(); + rhsRestParameter = true; + } + } + + Expression rhs = assignmentExpression(noIn); + + if (rhsRestParameter) { + rhs = ((IdentNode)rhs).setIsRestParameter(); + // Our only valid move is to end Expression here and continue with ArrowFunction. + // We've already checked that this is the parameter list of an arrow function (see above). + // RPAREN is next, so we'll finish the binary expression and drop out of the loop. + assert type == RPAREN; + } + + assignmentExpression = new BinaryNode(commaToken, assignmentExpression, rhs); + } + return assignmentExpression; + } + + private Expression expression(final int minPrecedence, final boolean noIn) { + return expression(unaryExpression(), minPrecedence, noIn); } private JoinPredecessorExpression joinPredecessorExpression() { @@ -3448,12 +4614,316 @@ loop: return lhs; } + /** + * AssignmentExpression. + * + * AssignmentExpression[In, Yield] : + * ConditionalExpression[?In, ?Yield] + * [+Yield] YieldExpression[?In] + * ArrowFunction[?In, ?Yield] + * LeftHandSideExpression[?Yield] = AssignmentExpression[?In, ?Yield] + * LeftHandSideExpression[?Yield] AssignmentOperator AssignmentExpression[?In, ?Yield] + */ protected Expression assignmentExpression(final boolean noIn) { // This method is protected so that subclass can get details // at assignment expression start point! - // Exclude commas in expression parsing. - return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); + if (type == YIELD && inGeneratorFunction() && isES6()) { + return yieldExpression(noIn); + } + + final long startToken = token; + final int startLine = line; + final Expression exprLhs = conditionalExpression(noIn); + + if (type == ARROW && isES6()) { + if (checkNoLineTerminator()) { + final Expression paramListExpr; + if (exprLhs instanceof ExpressionList) { + paramListExpr = (((ExpressionList)exprLhs).getExpressions().isEmpty() ? null : ((ExpressionList)exprLhs).getExpressions().get(0)); + } else { + paramListExpr = exprLhs; + } + return arrowFunction(startToken, startLine, paramListExpr); + } + } + assert !(exprLhs instanceof ExpressionList); + + if (isAssignmentOperator(type)) { + final boolean isAssign = type == ASSIGN; + if (isAssign) { + defaultNames.push(exprLhs); + } + try { + final long assignToken = token; + next(); + final Expression exprRhs = assignmentExpression(noIn); + return verifyAssignment(assignToken, exprLhs, exprRhs); + } finally { + if (isAssign) { + defaultNames.pop(); + } + } + } else { + return exprLhs; + } + } + + /** + * Is type one of {@code = *= /= %= += -= <<= >>= >>>= &= ^= |=}? + */ + private static boolean isAssignmentOperator(TokenType type) { + switch (type) { + case ASSIGN: + case ASSIGN_ADD: + case ASSIGN_BIT_AND: + case ASSIGN_BIT_OR: + case ASSIGN_BIT_XOR: + case ASSIGN_DIV: + case ASSIGN_MOD: + case ASSIGN_MUL: + case ASSIGN_SAR: + case ASSIGN_SHL: + case ASSIGN_SHR: + case ASSIGN_SUB: + return true; + } + return false; + } + + /** + * ConditionalExpression. + */ + private Expression conditionalExpression(boolean noIn) { + return expression(TERNARY.getPrecedence(), noIn); + } + + /** + * ArrowFunction. + * + * @param startToken start token of the ArrowParameters expression + * @param functionLine start line of the arrow function + * @param paramListExpr ArrowParameters expression or {@code null} for {@code ()} (empty list) + */ + private Expression arrowFunction(final long startToken, final int functionLine, final Expression paramListExpr) { + // caller needs to check that there's no LineTerminator between parameter list and arrow + assert type != ARROW || checkNoLineTerminator(); + expect(ARROW); + + final long functionToken = Token.recast(startToken, ARROW); + final IdentNode name = new IdentNode(functionToken, Token.descPosition(functionToken), "=>:" + functionLine); + final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.ARROW, functionLine, null); + functionNode.setFlag(FunctionNode.IS_ANONYMOUS); + + lc.push(functionNode); + try { + ParserContextBlockNode parameterBlock = newBlock(); + final List parameters; + try { + parameters = convertArrowFunctionParameterList(paramListExpr, functionLine); + functionNode.setParameters(parameters); + + if (!functionNode.isSimpleParameterList()) { + markEvalInArrowParameterList(parameterBlock); + } + } finally { + restoreBlock(parameterBlock); + } + Block functionBody = functionBody(functionNode); + + functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); + + verifyParameterList(parameters, functionNode); + + final FunctionNode function = createFunctionNode( + functionNode, + functionToken, + name, + parameters, + FunctionNode.Kind.ARROW, + functionLine, + functionBody); + return function; + } finally { + lc.pop(functionNode); + } + } + + private void markEvalInArrowParameterList(final ParserContextBlockNode parameterBlock) { + final Iterator iter = lc.getFunctions(); + final ParserContextFunctionNode current = iter.next(); + final ParserContextFunctionNode parent = iter.next(); + + if (parent.getFlag(FunctionNode.HAS_EVAL) != 0) { + // we might have flagged has-eval in the parent function during parsing the parameter list, + // if the parameter list contains eval; must tag arrow function as has-eval. + for (final Statement st : parameterBlock.getStatements()) { + st.accept(new NodeVisitor(new LexicalContext()) { + @Override + public boolean enterCallNode(final CallNode callNode) { + if (callNode.getFunction() instanceof IdentNode && ((IdentNode) callNode.getFunction()).getName().equals("eval")) { + current.setFlag(FunctionNode.HAS_EVAL); + } + return true; + } + }); + } + // TODO: function containing the arrow function should not be flagged has-eval + } + } + + private List convertArrowFunctionParameterList(final Expression paramListExpr, final int functionLine) { + final List parameters; + if (paramListExpr == null) { + // empty parameter list, i.e. () => + parameters = Collections.emptyList(); + } else if (paramListExpr instanceof IdentNode || paramListExpr.isTokenType(ASSIGN) || isDestructuringLhs(paramListExpr)) { + parameters = Collections.singletonList(verifyArrowParameter(paramListExpr, 0, functionLine)); + } else if (paramListExpr instanceof BinaryNode && Token.descType(paramListExpr.getToken()) == COMMARIGHT) { + parameters = new ArrayList<>(); + Expression car = paramListExpr; + do { + final Expression cdr = ((BinaryNode) car).rhs(); + parameters.add(0, verifyArrowParameter(cdr, parameters.size(), functionLine)); + car = ((BinaryNode) car).lhs(); + } while (car instanceof BinaryNode && Token.descType(car.getToken()) == COMMARIGHT); + parameters.add(0, verifyArrowParameter(car, parameters.size(), functionLine)); + } else { + throw error(AbstractParser.message("expected.arrow.parameter"), paramListExpr.getToken()); + } + return parameters; + } + + private IdentNode verifyArrowParameter(Expression param, int index, int paramLine) { + final String contextString = "function parameter"; + if (param instanceof IdentNode) { + IdentNode ident = (IdentNode)param; + verifyStrictIdent(ident, contextString); + ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); + if (currentFunction != null) { + currentFunction.addParameterBinding(ident); + } + return ident; + } + + if (param.isTokenType(ASSIGN)) { + Expression lhs = ((BinaryNode) param).lhs(); + long paramToken = lhs.getToken(); + Expression initializer = ((BinaryNode) param).rhs(); + if (lhs instanceof IdentNode) { + // default parameter + IdentNode ident = (IdentNode) lhs; + + ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); + if (currentFunction != null) { + BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); + TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); + BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value); + lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); + + currentFunction.addParameterBinding(ident); + currentFunction.setSimpleParameterList(false); + } + return ident; + } else if (isDestructuringLhs(lhs)) { + // binding pattern with initializer + // Introduce synthetic temporary parameter to capture the object to be destructured. + IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter().setIsDefaultParameter(); + verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString); + + ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); + if (currentFunction != null) { + BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); + TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); + BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, value); + lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); + } + return ident; + } + } else if (isDestructuringLhs(param)) { + // binding pattern + long paramToken = param.getToken(); + + // Introduce synthetic temporary parameter to capture the object to be destructured. + IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter(); + verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString); + + ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); + if (currentFunction != null) { + BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, ident); + lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); + } + return ident; + } + throw error(AbstractParser.message("invalid.arrow.parameter"), param.getToken()); + } + + private boolean checkNoLineTerminator() { + assert type == ARROW; + if (last == RPAREN) { + return true; + } else if (last == IDENT) { + return true; + } + for (int i = k - 1; i >= 0; i--) { + TokenType t = T(i); + switch (t) { + case RPAREN: + case IDENT: + return true; + case EOL: + return false; + case COMMENT: + continue; + default: + if (t.getKind() == TokenKind.FUTURESTRICT) { + return true; + } + return false; + } + } + return false; + } + + /** + * Peek ahead to see if what follows after the ellipsis is a rest parameter + * at the end of an arrow function parameter list. + */ + private boolean isRestParameterEndOfArrowFunctionParameterList() { + assert type == ELLIPSIS; + // find IDENT, RPAREN, ARROW, in that order, skipping over EOL (where allowed) and COMMENT + int i = 1; + for (;;) { + TokenType t = T(k + i++); + if (t == IDENT) { + break; + } else if (t == EOL || t == COMMENT) { + continue; + } else { + return false; + } + } + for (;;) { + TokenType t = T(k + i++); + if (t == RPAREN) { + break; + } else if (t == EOL || t == COMMENT) { + continue; + } else { + return false; + } + } + for (;;) { + TokenType t = T(k + i++); + if (t == ARROW) { + break; + } else if (t == COMMENT) { + continue; + } else { + return false; + } + } + return true; } /** @@ -3551,6 +5021,380 @@ loop: cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString)); } + + /** + * Parse a module. + * + * Module : + * ModuleBody? + * + * ModuleBody : + * ModuleItemList + */ + private FunctionNode module(final String moduleName) { + boolean oldStrictMode = isStrictMode; + try { + isStrictMode = true; // Module code is always strict mode code. (ES6 10.2.1) + + // Make a pseudo-token for the script holding its start and length. + int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish); + final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart); + final int functionLine = line; + + final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), moduleName); + final ParserContextFunctionNode script = createParserContextFunctionNode( + ident, + functionToken, + FunctionNode.Kind.MODULE, + functionLine, + Collections.emptyList()); + lc.push(script); + + final ParserContextModuleNode module = new ParserContextModuleNode(moduleName); + lc.push(module); + + final ParserContextBlockNode body = newBlock(); + + functionDeclarations = new ArrayList<>(); + moduleBody(); + addFunctionDeclarations(script); + functionDeclarations = null; + + restoreBlock(body); + body.setFlag(Block.NEEDS_SCOPE); + final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements()); + lc.pop(module); + lc.pop(script); + script.setLastToken(token); + + expect(EOF); + + script.setModule(module.createModule()); + return createFunctionNode(script, functionToken, ident, Collections.emptyList(), FunctionNode.Kind.MODULE, functionLine, programBody); + } finally { + isStrictMode = oldStrictMode; + } + } + + /** + * Parse module body. + * + * ModuleBody : + * ModuleItemList + * + * ModuleItemList : + * ModuleItem + * ModuleItemList ModuleItem + * + * ModuleItem : + * ImportDeclaration + * ExportDeclaration + * StatementListItem + */ + private void moduleBody() { + loop: + while (type != EOF) { + switch (type) { + case EOF: + break loop; + case IMPORT: + importDeclaration(); + break; + case EXPORT: + exportDeclaration(); + break; + default: + // StatementListItem + statement(true, false, false, false); + break; + } + } + } + + + /** + * Parse import declaration. + * + * ImportDeclaration : + * import ImportClause FromClause ; + * import ModuleSpecifier ; + * ImportClause : + * ImportedDefaultBinding + * NameSpaceImport + * NamedImports + * ImportedDefaultBinding , NameSpaceImport + * ImportedDefaultBinding , NamedImports + * ImportedDefaultBinding : + * ImportedBinding + * ModuleSpecifier : + * StringLiteral + * ImportedBinding : + * BindingIdentifier + */ + private void importDeclaration() { + expect(IMPORT); + final ParserContextModuleNode module = lc.getCurrentModule(); + if (type == STRING || type == ESCSTRING) { + // import ModuleSpecifier ; + final String moduleSpecifier = (String) getValue(); + next(); + module.addModuleRequest(moduleSpecifier); + } else { + // import ImportClause FromClause ; + List importEntries; + if (type == MUL) { + importEntries = Collections.singletonList(nameSpaceImport()); + } else if (type == LBRACE) { + importEntries = namedImports(); + } else if (isBindingIdentifier()) { + // ImportedDefaultBinding + final IdentNode importedDefaultBinding = bindingIdentifier("ImportedBinding"); + Module.ImportEntry defaultImport = Module.ImportEntry.importDefault(importedDefaultBinding.getName()); + + if (type == COMMARIGHT) { + next(); + importEntries = new ArrayList<>(); + if (type == MUL) { + importEntries.add(nameSpaceImport()); + } else if (type == LBRACE) { + importEntries.addAll(namedImports()); + } else { + throw error(AbstractParser.message("expected.named.import")); + } + } else { + importEntries = Collections.singletonList(defaultImport); + } + } else { + throw error(AbstractParser.message("expected.import")); + } + + final String moduleSpecifier = fromClause(); + module.addModuleRequest(moduleSpecifier); + for (int i = 0; i < importEntries.size(); i++) { + module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier)); + } + } + expect(SEMICOLON); + } + + /** + * NameSpaceImport : + * * as ImportedBinding + * + * @return imported binding identifier + */ + private Module.ImportEntry nameSpaceImport() { + assert type == MUL; + next(); + final long asToken = token; + final String as = (String) expectValue(IDENT); + if (!"as".equals(as)) { + throw error(AbstractParser.message("expected.as"), asToken); + } + final IdentNode localNameSpace = bindingIdentifier("ImportedBinding"); + return Module.ImportEntry.importStarAsNameSpaceFrom(localNameSpace.getName()); + } + + /** + * NamedImports : + * { } + * { ImportsList } + * { ImportsList , } + * ImportsList : + * ImportSpecifier + * ImportsList , ImportSpecifier + * ImportSpecifier : + * ImportedBinding + * IdentifierName as ImportedBinding + * ImportedBinding : + * BindingIdentifier + */ + private List namedImports() { + assert type == LBRACE; + next(); + List importEntries = new ArrayList<>(); + while (type != RBRACE) { + final boolean bindingIdentifier = isBindingIdentifier(); + final long nameToken = token; + final IdentNode importName = getIdentifierName(); + if (type == IDENT && "as".equals(getValue())) { + next(); + final IdentNode localName = bindingIdentifier("ImportedBinding"); + importEntries.add(Module.ImportEntry.importSpecifier(importName.getName(), localName.getName())); + } else if (!bindingIdentifier) { + throw error(AbstractParser.message("expected.binding.identifier"), nameToken); + } else { + importEntries.add(Module.ImportEntry.importSpecifier(importName.getName())); + } + if (type == COMMARIGHT) { + next(); + } else { + break; + } + } + expect(RBRACE); + return importEntries; + } + + /** + * FromClause : + * from ModuleSpecifier + */ + private String fromClause() { + final long fromToken = token; + final String name = (String) expectValue(IDENT); + if (!"from".equals(name)) { + throw error(AbstractParser.message("expected.from"), fromToken); + } + if (type == STRING || type == ESCSTRING) { + final String moduleSpecifier = (String) getValue(); + next(); + return moduleSpecifier; + } else { + throw error(expectMessage(STRING)); + } + } + + /** + * Parse export declaration. + * + * ExportDeclaration : + * export * FromClause ; + * export ExportClause FromClause ; + * export ExportClause ; + * export VariableStatement + * export Declaration + * export default HoistableDeclaration[Default] + * export default ClassDeclaration[Default] + * export default [lookahead !in {function, class}] AssignmentExpression[In] ; + */ + private void exportDeclaration() { + expect(EXPORT); + final ParserContextModuleNode module = lc.getCurrentModule(); + switch (type) { + case MUL: { + next(); + final String moduleRequest = fromClause(); + expect(SEMICOLON); + module.addModuleRequest(moduleRequest); + module.addStarExportEntry(Module.ExportEntry.exportStarFrom(moduleRequest)); + break; + } + case LBRACE: { + final List exportEntries = exportClause(); + if (type == IDENT && "from".equals(getValue())) { + final String moduleRequest = fromClause(); + module.addModuleRequest(moduleRequest); + for (Module.ExportEntry exportEntry : exportEntries) { + module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest)); + } + } else { + for (Module.ExportEntry exportEntry : exportEntries) { + module.addLocalExportEntry(exportEntry); + } + } + expect(SEMICOLON); + break; + } + case DEFAULT: + next(); + final Expression assignmentExpression; + IdentNode ident; + final int lineNumber = line; + final long rhsToken = token; + final boolean declaration; + switch (type) { + case FUNCTION: + assignmentExpression = functionExpression(false, true); + ident = ((FunctionNode) assignmentExpression).getIdent(); + declaration = true; + break; + case CLASS: + assignmentExpression = classDeclaration(true); + ident = ((ClassNode) assignmentExpression).getIdent(); + declaration = true; + break; + default: + assignmentExpression = assignmentExpression(false); + ident = null; + declaration = false; + break; + } + if (ident != null) { + module.addLocalExportEntry(Module.ExportEntry.exportDefault(ident.getName())); + } else { + ident = createIdentNode(Token.recast(rhsToken, IDENT), finish, Module.DEFAULT_EXPORT_BINDING_NAME); + lc.appendStatementToCurrentNode(new VarNode(lineNumber, Token.recast(rhsToken, LET), finish, ident, assignmentExpression)); + if (!declaration) { + expect(SEMICOLON); + } + module.addLocalExportEntry(Module.ExportEntry.exportDefault()); + } + break; + case VAR: + case LET: + case CONST: + final List statements = lc.getCurrentBlock().getStatements(); + final int previousEnd = statements.size(); + variableStatement(type); + for (final Statement statement : statements.subList(previousEnd, statements.size())) { + if (statement instanceof VarNode) { + module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName().getName())); + } + } + break; + case CLASS: { + final ClassNode classDeclaration = classDeclaration(false); + module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent().getName())); + break; + } + case FUNCTION: { + final FunctionNode functionDeclaration = (FunctionNode) functionExpression(true, true); + module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent().getName())); + break; + } + default: + throw error(AbstractParser.message("invalid.export"), token); + } + } + + /** + * ExportClause : + * { } + * { ExportsList } + * { ExportsList , } + * ExportsList : + * ExportSpecifier + * ExportsList , ExportSpecifier + * ExportSpecifier : + * IdentifierName + * IdentifierName as IdentifierName + * + * @return a list of ExportSpecifiers + */ + private List exportClause() { + assert type == LBRACE; + next(); + List exports = new ArrayList<>(); + while (type != RBRACE) { + final IdentNode localName = getIdentifierName(); + if (type == IDENT && "as".equals(getValue())) { + next(); + final IdentNode exportName = getIdentifierName(); + exports.add(Module.ExportEntry.exportSpecifier(exportName.getName(), localName.getName())); + } else { + exports.add(Module.ExportEntry.exportSpecifier(localName.getName())); + } + if (type == COMMARIGHT) { + next(); + } else { + break; + } + } + expect(RBRACE); + return exports; + } + @Override public String toString() { return "'JavaScript Parsing'"; @@ -3564,6 +5408,12 @@ loop: if (!flaggedCurrentFn) { fn.setFlag(FunctionNode.HAS_EVAL); flaggedCurrentFn = true; + if (fn.getKind() == FunctionNode.Kind.ARROW) { + // possible use of this in an eval that's nested in an arrow function, e.g.: + // function fun(){ return (() => eval("this"))(); }; + markThis(lc); + markNewTarget(lc); + } } else { fn.setFlag(FunctionNode.HAS_NESTED_EVAL); } @@ -3583,4 +5433,55 @@ loop: private void appendStatement(final Statement statement) { lc.appendStatementToCurrentNode(statement); } + + private static void markSuperCall(final ParserContext lc) { + final Iterator iter = lc.getFunctions(); + while (iter.hasNext()) { + final ParserContextFunctionNode fn = iter.next(); + if (fn.getKind() != FunctionNode.Kind.ARROW) { + assert fn.isSubclassConstructor(); + fn.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER); + break; + } + } + } + + private ParserContextFunctionNode getCurrentNonArrowFunction() { + final Iterator iter = lc.getFunctions(); + while (iter.hasNext()) { + final ParserContextFunctionNode fn = iter.next(); + if (fn.getKind() != FunctionNode.Kind.ARROW) { + return fn; + } + } + return null; + } + + private static void markThis(final ParserContext lc) { + final Iterator iter = lc.getFunctions(); + while (iter.hasNext()) { + final ParserContextFunctionNode fn = iter.next(); + fn.setFlag(FunctionNode.USES_THIS); + if (fn.getKind() != FunctionNode.Kind.ARROW) { + break; + } + } + } + + private static void markNewTarget(final ParserContext lc) { + final Iterator iter = lc.getFunctions(); + while (iter.hasNext()) { + final ParserContextFunctionNode fn = iter.next(); + if (fn.getKind() != FunctionNode.Kind.ARROW) { + if (!fn.isProgram()) { + fn.setFlag(FunctionNode.ES6_USES_NEW_TARGET); + } + break; + } + } + } + + private boolean inGeneratorFunction() { + return lc.getCurrentFunction().getKind() == FunctionNode.Kind.GENERATOR; + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java index b2de378265b..fd2476a7c18 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java @@ -278,7 +278,12 @@ class ParserContext { return new NodeIterator<>(ParserContextFunctionNode.class); } - private class NodeIterator implements Iterator { + public ParserContextModuleNode getCurrentModule() { + final Iterator iter = new NodeIterator<>(ParserContextModuleNode.class, getCurrentFunction()); + return iter.hasNext() ? iter.next() : null; + } + + private class NodeIterator implements Iterator { private int index; private T next; private final Class clazz; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java index 5418caff915..cfd8b293071 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java @@ -24,10 +24,12 @@ */ package jdk.nashorn.internal.parser; +import java.util.HashSet; import java.util.List; import jdk.nashorn.internal.codegen.Namespace; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.IdentNode; +import jdk.nashorn.internal.ir.Module; /** * ParserContextNode that represents a function that is currently being parsed @@ -46,11 +48,11 @@ class ParserContextFunctionNode extends ParserContextBaseNode { /** Line number for function declaration */ private final int line; - /** Function node kind, see {@link FunctionNode#Kind} */ + /** Function node kind, see {@link FunctionNode.Kind} */ private final FunctionNode.Kind kind; /** List of parameter identifiers for function */ - private final List parameters; + private List parameters; /** Token for function start */ private final long token; @@ -61,6 +63,14 @@ class ParserContextFunctionNode extends ParserContextBaseNode { /** Opaque node for parser end state, see {@link Parser} */ private Object endParserState; + private HashSet parameterBoundNames; + private IdentNode duplicateParameterBinding; + private boolean simpleParameterList = true; + + private Module module; + + private int debugFlags; + /** * @param token The token for the function * @param ident External function name @@ -155,6 +165,10 @@ class ParserContextFunctionNode extends ParserContextBaseNode { return parameters; } + void setParameters(List parameters) { + this.parameters = parameters; + } + /** * Set last token * @param token New last token @@ -194,4 +208,70 @@ class ParserContextFunctionNode extends ParserContextBaseNode { public int getId() { return isProgram() ? -1 : Token.descPosition(token); } + + /** + * Returns the debug flags for this function. + * + * @return the debug flags + */ + int getDebugFlags() { + return debugFlags; + } + + /** + * Sets a debug flag for this function. + * + * @param debugFlag the debug flag + */ + void setDebugFlag(final int debugFlag) { + debugFlags |= debugFlag; + } + + public boolean isMethod() { + return getFlag(FunctionNode.ES6_IS_METHOD) != 0; + } + + public boolean isClassConstructor() { + return getFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR) != 0; + } + + public boolean isSubclassConstructor() { + return getFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR) != 0; + } + + boolean addParameterBinding(final IdentNode bindingIdentifier) { + if (Parser.isArguments(bindingIdentifier)) { + setFlag(FunctionNode.DEFINES_ARGUMENTS); + } + + if (parameterBoundNames == null) { + parameterBoundNames = new HashSet<>(); + } + if (parameterBoundNames.add(bindingIdentifier.getName())) { + return true; + } else { + duplicateParameterBinding = bindingIdentifier; + return false; + } + } + + public IdentNode getDuplicateParameterBinding() { + return duplicateParameterBinding; + } + + public boolean isSimpleParameterList() { + return simpleParameterList; + } + + public void setSimpleParameterList(final boolean simpleParameterList) { + this.simpleParameterList = simpleParameterList; + } + + public Module getModule() { + return module; + } + + public void setModule(final Module module) { + this.module = module; + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextModuleNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextModuleNode.java new file mode 100644 index 00000000000..0c883351682 --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextModuleNode.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.nashorn.internal.parser; + +import java.util.ArrayList; +import java.util.List; + +import jdk.nashorn.internal.ir.Module; +import jdk.nashorn.internal.ir.Module.ExportEntry; +import jdk.nashorn.internal.ir.Module.ImportEntry; + +/** + * ParserContextNode that represents a module. + */ +class ParserContextModuleNode extends ParserContextBaseNode { + + /** Module name. */ + private final String name; + + private List requestedModules = new ArrayList<>(); + private List importEntries = new ArrayList<>(); + private List localExportEntries = new ArrayList<>(); + private List indirectExportEntries = new ArrayList<>(); + private List starExportEntries = new ArrayList<>(); + + /** + * Constructor. + * + * @param name name of the module + */ + ParserContextModuleNode(final String name) { + this.name = name; + } + + /** + * Returns the name of the module. + * + * @return name of the module + */ + public String getModuleName() { + return name; + } + + public void addModuleRequest(final String moduleRequest) { + requestedModules.add(moduleRequest); + } + + public void addImportEntry(final ImportEntry importEntry) { + importEntries.add(importEntry); + } + + public void addLocalExportEntry(final ExportEntry exportEntry) { + localExportEntries.add(exportEntry); + } + + public void addIndirectExportEntry(final ExportEntry exportEntry) { + indirectExportEntries.add(exportEntry); + } + + public void addStarExportEntry(final ExportEntry exportEntry) { + starExportEntries.add(exportEntry); + } + + public Module createModule() { + return new Module(requestedModules, importEntries, localExportEntries, indirectExportEntries, starExportEntries); + } +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java index af9f40a4e8c..080c147d588 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java @@ -82,7 +82,7 @@ public enum TokenType { ASSIGN (BINARY, "=", 2, false), EQ (BINARY, "==", 9, true), EQ_STRICT (BINARY, "===", 9, true), - BIND (BINARY, "=>", 9, true), + ARROW (BINARY, "=>", 2, true), GT (BINARY, ">", 10, true), GE (BINARY, ">=", 10, true), SAR (BINARY, ">>", 11, true), @@ -100,6 +100,7 @@ public enum TokenType { OR (BINARY, "||", 4, true), RBRACE (BRACKET, "}"), BIT_NOT (UNARY, "~", 14, false), + ELLIPSIS (UNARY, "..."), // ECMA 7.6.1.1 Keywords, 7.6.1.2 Future Reserved Words. // All other Java keywords are commented out. @@ -190,7 +191,10 @@ public enum TokenType { COMMALEFT (IR, null), DECPOSTFIX (IR, null), - INCPOSTFIX (IR, null); + INCPOSTFIX (IR, null), + SPREAD_ARGUMENT(IR, null), + SPREAD_ARRAY (IR, null), + YIELD_STAR (IR, null); /** Next token kind in token lookup table. */ private TokenType next; @@ -251,7 +255,6 @@ public enum TokenType { return kind == BINARY && (!noIn || this != IN) && precedence != 0; } - public int getLength() { assert name != null : "Token name not set"; return name.length(); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java index 64a67d89eb1..94f224e2b22 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java @@ -1403,11 +1403,11 @@ public final class Context { return null; } - if (env._print_ast || functionNode.getFlag(FunctionNode.IS_PRINT_AST)) { + if (env._print_ast || functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) { getErr().println(new ASTWriter(functionNode)); } - if (env._print_parse || functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) { + if (env._print_parse || functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) { getErr().println(new PrintVisitor(functionNode, true, false)); } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties index fb5ccf0cbdf..0116fb4d452 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -63,6 +63,27 @@ parser.error.trailing.comma.in.json=Trailing comma is not allowed in JSON parser.error.missing.const.assignment=Missing assignment to constant "{0}" parser.error.unterminated.template.expression=Expected } after expression in template literal +# ES6 mode error messages +parser.error.multiple.constructors=Class contains more than one constructor +parser.error.generator.constructor=Class constructor must not be a generator +parser.error.accessor.constructor=Class constructor must not be an accessor +parser.error.static.prototype.method=Static class method must not be named 'prototype' +parser.error.missing.destructuring.assignment=Missing assignment in destructuring declaration +parser.error.let.binding.for='let' is not a valid binding name in a for loop +parser.error.invalid.export=invalid export declaration +parser.error.expected.binding=expected BindingIdentifier or BindingPattern +parser.error.multiple.proto.key=property name __proto__ appears more than once in object literal +parser.error.new.target.in.function=new.target expression is only allowed in functions +parser.error.expected.target=expected 'target' +parser.error.invalid.super=invalid use of keyword super +parser.error.expected.arrow.parameter=expected arrow function parameter list +parser.error.invalid.arrow.parameter=invalid arrow function parameter +parser.error.expected.named.import=expected NameSpaceImport or NamedImports +parser.error.expected.import=expected ImportClause or ModuleSpecifier +parser.error.expected.as=expected 'as' +parser.error.expected.binding.identifier=expected BindingIdentifier +parser.error.expected.from=expected 'from' + # strict mode error messages parser.error.strict.no.with="with" statement cannot be used in strict mode parser.error.strict.name="{0}" cannot be used as {1} in strict mode diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java index 5142fcd46c1..a7bee7c286b 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java @@ -438,6 +438,9 @@ public class Shell implements PartialParser { final File file = new File(fileName); final ScriptFunction script = context.compileScript(sourceFor(fileName, file), global); if (script == null || errors.getNumberOfErrors() != 0) { + if (context.getEnv()._parse_only && !errors.hasErrors()) { + continue; // No error, continue to consume all files in list + } return COMPILATION_ERROR; } diff --git a/nashorn/test/script/basic/yield.js b/nashorn/test/script/basic/es6/parser-es6.js similarity index 50% rename from nashorn/test/script/basic/yield.js rename to nashorn/test/script/basic/es6/parser-es6.js index 935f6402ea6..f3d35eb4126 100644 --- a/nashorn/test/script/basic/yield.js +++ b/nashorn/test/script/basic/es6/parser-es6.js @@ -1,34 +1,94 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * 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. */ - /** - * Check yield keyword is parsed and yield statement does nothing (yet). + * JDK-8134503: support ES6 parsing in Nashorn * * @test - * @run + * @option --language=es6 + * @option --parse-only */ -function func() { - yield 2; + +[].map(v => v + 1); + +class A extends B.C { + constructor(a, b) { + super(a, b); + } + someMethod(c) { + super.someMethod(); + } + get g() { + return this.g; + } + set s(t) { + this.t = t; + } + static m() { + return k; + } } + +var obj = { + __proto__: theProtoObj, + handler, + r() { + return super.m(); + }, + [ '__' + (() => 'x')() ]: 1, + *q (x, y) { + yield 1; + } +}; + +var [a, , b] = [1, 2, 3]; + +var { x: a, y: { z: b }, w: c } = abc(); + +var {a, b, c} = abc(); + +var o = { x, y }; + +function g({name: x}) { + return x; +} + +foo(a, ...b); + +var c = [ ...s ]; + +var [a] = []; + +var [a = 1] = []; + + +var f = { + [Symbol.iterator]: function*() { + var cur = 1; + for (;;) { + yield cur; + } + } +}; + diff --git a/nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED b/nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED index bda3808e6ca..f7112ce951a 100644 --- a/nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED +++ b/nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED @@ -1,3 +1,3 @@ -test/script/error/NASHORN-154/function_mult_params_in_strict.js:38:14 strict mode function cannot have duplicate parameter name "x" +test/script/error/NASHORN-154/function_mult_params_in_strict.js:38:17 strict mode function cannot have duplicate parameter name "x" function func(x, x) {} - ^ + ^ diff --git a/nashorn/test/script/nosecurity/parserapi.js.EXPECTED b/nashorn/test/script/nosecurity/parserapi.js.EXPECTED index eabe2d4cae8..8fbd95117da 100644 --- a/nashorn/test/script/nosecurity/parserapi.js.EXPECTED +++ b/nashorn/test/script/nosecurity/parserapi.js.EXPECTED @@ -100,7 +100,7 @@ "startPosition": "1181", "properties": [ { - "endPosition": "1185", + "endPosition": "1187", "kind": "PROPERTY", "value": { "endPosition": "1187", @@ -2386,7 +2386,7 @@ "startPosition": "1139", "properties": [ { - "endPosition": "1143", + "endPosition": "1146", "kind": "PROPERTY", "value": { "endPosition": "1146", @@ -2403,7 +2403,7 @@ } }, { - "endPosition": "1150", + "endPosition": "1152", "kind": "PROPERTY", "value": { "endPosition": "1152", @@ -2443,7 +2443,7 @@ "startPosition": "1160", "properties": [ { - "endPosition": "1166", + "endPosition": "1169", "kind": "PROPERTY", "value": { "endPosition": "1169", @@ -2460,7 +2460,7 @@ } }, { - "endPosition": "1175", + "endPosition": "1177", "kind": "PROPERTY", "value": { "endPosition": "1177", @@ -2914,7 +2914,7 @@ "startPosition": "1178", "properties": [ { - "endPosition": "1182", + "endPosition": "1184", "kind": "PROPERTY", "value": { "endPosition": "1184", @@ -3395,7 +3395,7 @@ "startPosition": "1200", "properties": [ { - "endPosition": "1206", + "endPosition": "1214", "kind": "PROPERTY", "value": { "endPosition": "1214", @@ -4709,11 +4709,11 @@ , { "fileName": "parsernegativetests/strict_repeatparam.js", - "code": "ident (1119, 1)", - "columnNumber": "14", + "code": "ident (1122, 1)", + "columnNumber": "17", "kind": "ERROR", - "position": "1119", - "message": "parsernegativetests/strict_repeatparam.js:31:14 strict mode function cannot have duplicate parameter name \"x\"\nfunction func(x, x) {}\n ^", + "position": "1122", + "message": "parsernegativetests/strict_repeatparam.js:31:17 strict mode function cannot have duplicate parameter name \"x\"\nfunction func(x, x) {}\n ^", "lineNumber": "31" } , diff --git a/nashorn/test/script/nosecurity/parserapi_strict.js.EXPECTED b/nashorn/test/script/nosecurity/parserapi_strict.js.EXPECTED index 833637a598d..3b4ab0665c6 100644 --- a/nashorn/test/script/nosecurity/parserapi_strict.js.EXPECTED +++ b/nashorn/test/script/nosecurity/parserapi_strict.js.EXPECTED @@ -6,10 +6,10 @@ with_stat.js:2:7 Expected ; but found ) with({}) {} ^ -repeat_param.js:2:15 strict mode function cannot have duplicate parameter name "x" +repeat_param.js:2:18 strict mode function cannot have duplicate parameter name "x" function func(x, x) {} - ^ + ^ repeat_prop.js:2:22 Property "foo" already defined var obj = { foo: 34, foo: 'hello' }; diff --git a/nashorn/test/script/nosecurity/treeapi/array_literal.js.EXPECTED b/nashorn/test/script/nosecurity/treeapi/array_literal.js.EXPECTED index 8ea2c83773c..e4a88212dc7 100644 --- a/nashorn/test/script/nosecurity/treeapi/array_literal.js.EXPECTED +++ b/nashorn/test/script/nosecurity/treeapi/array_literal.js.EXPECTED @@ -74,7 +74,7 @@ "properties": [ { "getter": "null", - "endPosition": "74", + "endPosition": "76", "kind": "PROPERTY", "setter": "null", "value": { diff --git a/nashorn/test/script/nosecurity/treeapi/objectLiteral.js.EXPECTED b/nashorn/test/script/nosecurity/treeapi/objectLiteral.js.EXPECTED index 04ec80ac815..3584dea2f73 100644 --- a/nashorn/test/script/nosecurity/treeapi/objectLiteral.js.EXPECTED +++ b/nashorn/test/script/nosecurity/treeapi/objectLiteral.js.EXPECTED @@ -6,7 +6,7 @@ "properties": [ { "getter": "null", - "endPosition": "8", + "endPosition": "12", "kind": "PROPERTY", "setter": "null", "value": { @@ -38,7 +38,7 @@ "properties": [ { "getter": "null", - "endPosition": "34", + "endPosition": "37", "kind": "PROPERTY", "setter": "null", "value": { @@ -57,7 +57,7 @@ }, { "getter": "null", - "endPosition": "41", + "endPosition": "43", "kind": "PROPERTY", "setter": "null", "value": { @@ -83,7 +83,7 @@ "properties": [ { "getter": "null", - "endPosition": "57", + "endPosition": "60", "kind": "PROPERTY", "setter": "null", "value": { @@ -102,7 +102,7 @@ }, { "getter": "null", - "endPosition": "66", + "endPosition": "68", "kind": "PROPERTY", "setter": "null", "value": { diff --git a/nashorn/test/script/nosecurity/treeapi/property.js.EXPECTED b/nashorn/test/script/nosecurity/treeapi/property.js.EXPECTED index b4e3c79eb80..f4c8d4ce0f9 100644 --- a/nashorn/test/script/nosecurity/treeapi/property.js.EXPECTED +++ b/nashorn/test/script/nosecurity/treeapi/property.js.EXPECTED @@ -1,7 +1,7 @@ [ { "getter": "null", - "endPosition": "17", + "endPosition": "22", "kind": "PROPERTY", "setter": "null", "value": { @@ -20,7 +20,7 @@ }, { "getter": "null", - "endPosition": "31", + "endPosition": "38", "kind": "PROPERTY", "setter": "null", "value": { @@ -45,7 +45,7 @@ }, { "getter": "null", - "endPosition": "46", + "endPosition": "61", "kind": "PROPERTY", "setter": "null", "value": { @@ -72,7 +72,7 @@ }, { "getter": "null", - "endPosition": "69", + "endPosition": "72", "kind": "PROPERTY", "setter": "null", "value": { diff --git a/nashorn/test/script/nosecurity/treeapi/throw.js.EXPECTED b/nashorn/test/script/nosecurity/treeapi/throw.js.EXPECTED index 45afd9cc815..928072707e7 100644 --- a/nashorn/test/script/nosecurity/treeapi/throw.js.EXPECTED +++ b/nashorn/test/script/nosecurity/treeapi/throw.js.EXPECTED @@ -80,7 +80,7 @@ "properties": [ { "getter": "null", - "endPosition": "97", + "endPosition": "105", "kind": "PROPERTY", "setter": "null", "value": { diff --git a/nashorn/test/script/nosecurity/treeapi/with.js.EXPECTED b/nashorn/test/script/nosecurity/treeapi/with.js.EXPECTED index 1fdf0807665..5720bc9d46e 100644 --- a/nashorn/test/script/nosecurity/treeapi/with.js.EXPECTED +++ b/nashorn/test/script/nosecurity/treeapi/with.js.EXPECTED @@ -49,7 +49,7 @@ "properties": [ { "getter": "null", - "endPosition": "34", + "endPosition": "39", "kind": "PROPERTY", "setter": "null", "value": { diff --git a/nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java b/nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java index 3e3c9512756..e52d2a66373 100644 --- a/nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java +++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java @@ -194,9 +194,9 @@ public final class ScriptRunnable extends AbstractScriptRunnable implements ITes pb.redirectError(errorFileHandle); final Process process = pb.start(); - process.waitFor(); + final int exitCode = process.waitFor(); - if (errorFileHandle.length() > 0) { + if (exitCode != 0 || errorFileHandle.length() > 0) { if (expectRunFailure) { return; } From 1e0d1458a251c5696d9b613c7bb03472eb44065f Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 27 Apr 2016 18:04:16 +0200 Subject: [PATCH 159/222] 8148568: LoggerFinder.getLogger and LoggerFinder.getLocalizedLogger should take a Module argument instead of a Class Changes System.LoggerFinder methods to take a Module argument instead of a Class. Reviewed-by: mchung --- .../share/classes/java/lang/System.java | 67 +++++++++-------- .../internal/logger/DefaultLoggerFinder.java | 33 ++++++--- .../jdk/internal/logger/LazyLoggers.java | 73 ++++++++++--------- .../sun/util/logging/PlatformLogger.java | 9 ++- .../classes/java/util/logging/LogManager.java | 48 ++++++++---- .../classes/java/util/logging/Logger.java | 27 ++++--- .../logging/internal/LoggingProviderImpl.java | 20 ++--- .../Logger/custom/CustomLoggerTest.java | 53 ++++++++++---- .../BaseLoggerFinder.java | 3 +- .../BaseLoggerFinderTest.java | 32 ++++---- .../TestLoggerFinder.java | 5 +- .../DefaultLoggerFinderTest.java | 32 ++++---- .../BaseDefaultLoggerFinderTest.java | 16 ++-- .../BaseLoggerBridgeTest.java | 27 ++++--- .../BasePlatformLoggerTest.java | 10 ++- .../BootstrapLoggerAPIsTest.java | 4 +- .../BootstrapLogger/BootstrapLoggerTest.java | 5 +- .../LoggerBridgeTest/LoggerBridgeTest.java | 41 +++++++---- .../LoggerFinderLoaderTest.java | 9 ++- .../PlatformLoggerBridgeTest.java | 7 +- .../internal/api/LoggerFinderAPITest.java | 6 +- .../backend/LoggerFinderBackendTest.java | 39 +++++----- .../DefaultLoggerBridgeTest.java | 19 ++--- .../DefaultPlatformLoggerTest.java | 5 +- .../sun/util/logging/PlatformLoggerTest.java | 2 +- 25 files changed, 342 insertions(+), 250 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java index 2ddd37f5da1..d6e80e71908 100644 --- a/jdk/src/java.base/share/classes/java/lang/System.java +++ b/jdk/src/java.base/share/classes/java/lang/System.java @@ -1155,8 +1155,9 @@ public final class System { * @param level the log message level. * @param msg the string message (or a key in the message catalog, if * this logger is a {@link - * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class) - * localized logger}); can be {@code null}. + * LoggerFinder#getLocalizedLogger(java.lang.String, + * java.util.ResourceBundle, java.lang.reflect.Module) localized logger}); + * can be {@code null}. * * @throws NullPointerException if {@code level} is {@code null}. */ @@ -1222,8 +1223,9 @@ public final class System { * @param level the log message level. * @param msg the string message (or a key in the message catalog, if * this logger is a {@link - * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class) - * localized logger}); can be {@code null}. + * LoggerFinder#getLocalizedLogger(java.lang.String, + * java.util.ResourceBundle, java.lang.reflect.Module) localized logger}); + * can be {@code null}. * @param thrown a {@code Throwable} associated with the log message; * can be {@code null}. * @@ -1270,8 +1272,9 @@ public final class System { * @param format the string message format in {@link * java.text.MessageFormat} format, (or a key in the message * catalog, if this logger is a {@link - * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class) - * localized logger}); can be {@code null}. + * LoggerFinder#getLocalizedLogger(java.lang.String, + * java.util.ResourceBundle, java.lang.reflect.Module) localized logger}); + * can be {@code null}. * @param params an optional list of parameters to the message (may be * none). * @@ -1453,30 +1456,30 @@ public final class System { /** * Returns an instance of {@link Logger Logger} - * for the given {@code caller}. + * for the given {@code module}. * * @param name the name of the logger. - * @param caller the class for which the logger is being requested. + * @param module the module for which the logger is being requested. * - * @return a {@link Logger logger} suitable for the given caller's - * use. + * @return a {@link Logger logger} suitable for use within the given + * module. * @throws NullPointerException if {@code name} is {@code null} or - * {@code caller} is {@code null}. + * {@code module} is {@code null}. * @throws SecurityException if a security manager is present and its * {@code checkPermission} method doesn't allow the * {@code RuntimePermission("loggerFinder")}. */ - public abstract Logger getLogger(String name, /* Module */ Class caller); + public abstract Logger getLogger(String name, Module module); /** * Returns a localizable instance of {@link Logger Logger} - * for the given {@code caller}. + * for the given {@code module}. * The returned logger will use the provided resource bundle for * message localization. * * @implSpec By default, this method calls {@link - * #getLogger(java.lang.String, java.lang.Class) - * this.getLogger(name, caller)} to obtain a logger, then wraps that + * #getLogger(java.lang.String, java.lang.reflect.Module) + * this.getLogger(name, module)} to obtain a logger, then wraps that * logger in a {@link Logger} instance where all methods that do not * take a {@link ResourceBundle} as parameter are redirected to one * which does - passing the given {@code bundle} for @@ -1499,19 +1502,19 @@ public final class System { * * @param name the name of the logger. * @param bundle a resource bundle; can be {@code null}. - * @param caller the class for which the logger is being requested. + * @param module the module for which the logger is being requested. * @return an instance of {@link Logger Logger} which will use the * provided resource bundle for message localization. * * @throws NullPointerException if {@code name} is {@code null} or - * {@code caller} is {@code null}. + * {@code module} is {@code null}. * @throws SecurityException if a security manager is present and its * {@code checkPermission} method doesn't allow the * {@code RuntimePermission("loggerFinder")}. */ public Logger getLocalizedLogger(String name, ResourceBundle bundle, - /* Module */ Class caller) { - return new LocalizedLoggerWrapper<>(getLogger(name, caller), bundle); + Module module) { + return new LocalizedLoggerWrapper<>(getLogger(name, module), bundle); } /** @@ -1558,12 +1561,13 @@ public final class System { * * @implSpec * Instances returned by this method route messages to loggers - * obtained by calling {@link LoggerFinder#getLogger(java.lang.String, java.lang.Class) - * LoggerFinder.getLogger(name, caller)}. + * obtained by calling {@link LoggerFinder#getLogger(java.lang.String, + * java.lang.reflect.Module) LoggerFinder.getLogger(name, module)}, where + * {@code module} is the caller's module. * * @apiNote * This method may defer calling the {@link - * LoggerFinder#getLogger(java.lang.String, java.lang.Class) + * LoggerFinder#getLogger(java.lang.String, java.lang.reflect.Module) * LoggerFinder.getLogger} method to create an actual logger supplied by * the logging backend, for instance, to allow loggers to be obtained during * the system initialization time. @@ -1579,7 +1583,7 @@ public final class System { public static Logger getLogger(String name) { Objects.requireNonNull(name); final Class caller = Reflection.getCallerClass(); - return LazyLoggers.getLogger(name, caller); + return LazyLoggers.getLogger(name, caller.getModule()); } /** @@ -1591,8 +1595,9 @@ public final class System { * @implSpec * The returned logger will perform message localization as specified * by {@link LoggerFinder#getLocalizedLogger(java.lang.String, - * java.util.ResourceBundle, java.lang.Class) - * LoggerFinder.getLocalizedLogger(name, bundle, caller}. + * java.util.ResourceBundle, java.lang.reflect.Module) + * LoggerFinder.getLocalizedLogger(name, bundle, module}, where + * {@code module} is the caller's module. * * @apiNote * This method is intended to be used after the system is fully initialized. @@ -1624,12 +1629,14 @@ public final class System { // Bootstrap sensitive classes in the JDK do not use resource bundles // when logging. This could be revisited later, if it needs to. if (sm != null) { - return AccessController.doPrivileged((PrivilegedAction) - () -> LoggerFinder.accessProvider().getLocalizedLogger(name, rb, caller), - null, - LoggerFinder.LOGGERFINDER_PERMISSION); + final PrivilegedAction pa = + () -> LoggerFinder.accessProvider() + .getLocalizedLogger(name, rb, caller.getModule()); + return AccessController.doPrivileged(pa, null, + LoggerFinder.LOGGERFINDER_PERMISSION); } - return LoggerFinder.accessProvider().getLocalizedLogger(name, rb, caller); + return LoggerFinder.accessProvider() + .getLocalizedLogger(name, rb, caller.getModule()); } /** diff --git a/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java b/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java index da255a3e2b8..e24fcad2bd4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java @@ -33,6 +33,9 @@ import java.util.function.Function; import java.lang.System.LoggerFinder; import java.lang.System.Logger; import java.lang.ref.ReferenceQueue; +import java.lang.reflect.Module; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Collection; import java.util.ResourceBundle; @@ -129,41 +132,49 @@ public class DefaultLoggerFinder extends LoggerFinder { return w; } - final static SharedLoggers system = new SharedLoggers(); final static SharedLoggers application = new SharedLoggers(); } + public static boolean isSystem(Module m) { + ClassLoader cl = AccessController.doPrivileged(new PrivilegedAction<>() { + @Override + public ClassLoader run() { + return m.getClassLoader(); + } + }); + return cl == null; + } + @Override - public final Logger getLogger(String name, /* Module */ Class caller) { + public final Logger getLogger(String name, Module module) { checkPermission(); - return demandLoggerFor(name, caller); + return demandLoggerFor(name, module); } @Override public final Logger getLocalizedLogger(String name, ResourceBundle bundle, - /* Module */ Class caller) { - return super.getLocalizedLogger(name, bundle, caller); + Module module) { + return super.getLocalizedLogger(name, bundle, module); } - - /** - * Returns a {@link Logger logger} suitable for the caller usage. + * Returns a {@link Logger logger} suitable for use within the + * given {@code module}. * * @implSpec The default implementation for this method is to return a * simple logger that will print all messages of INFO level and above * to the console. That simple logger is not configurable. * * @param name The name of the logger. - * @param caller The class on behalf of which the logger is created. + * @param module The module on behalf of which the logger is created. * @return A {@link Logger logger} suitable for the application usage. * @throws SecurityException if the calling code does not have the * {@code RuntimePermission("loggerFinder")}. */ - protected Logger demandLoggerFor(String name, /* Module */ Class caller) { + protected Logger demandLoggerFor(String name, Module module) { checkPermission(); - if (caller.getClassLoader() == null) { + if (isSystem(module)) { return SharedLoggers.system.get(SimpleConsoleLogger::makeSimpleLogger, name); } else { return SharedLoggers.application.get(SimpleConsoleLogger::makeSimpleLogger, name); diff --git a/jdk/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java b/jdk/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java index 04b64ea98b1..6c65426ca8e 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java +++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java @@ -31,6 +31,7 @@ import java.util.function.BiFunction; import java.lang.System.LoggerFinder; import java.lang.System.Logger; import java.lang.ref.WeakReference; +import java.lang.reflect.Module; import java.util.Objects; import jdk.internal.misc.VM; import sun.util.logging.PlatformLogger; @@ -59,15 +60,15 @@ public final class LazyLoggers { * A factory method to create an SPI logger. * Usually, this will be something like LazyLoggers::getSystemLogger. */ - final BiFunction, L> loggerSupplier; + final BiFunction loggerSupplier; - public LazyLoggerFactories(BiFunction, L> loggerSupplier) { + public LazyLoggerFactories(BiFunction loggerSupplier) { this(Objects.requireNonNull(loggerSupplier), (Void)null); } - private LazyLoggerFactories(BiFunction, L> loggerSupplier, + private LazyLoggerFactories(BiFunction loggerSupplier, Void unused) { this.loggerSupplier = loggerSupplier; } @@ -107,8 +108,8 @@ public final class LazyLoggers { // The factories that will be used to create the logger lazyly final LazyLoggerFactories factories; - // We need to pass the actual caller when creating the logger. - private final WeakReference> callerRef; + // We need to pass the actual caller module when creating the logger. + private final WeakReference moduleRef; // The name of the logger that will be created lazyly final String name; @@ -121,17 +122,17 @@ public final class LazyLoggers { private LazyLoggerAccessor(String name, LazyLoggerFactories factories, - Class caller) { + Module module) { this(Objects.requireNonNull(name), Objects.requireNonNull(factories), - Objects.requireNonNull(caller), null); + Objects.requireNonNull(module), null); } private LazyLoggerAccessor(String name, LazyLoggerFactories factories, - Class caller, Void unused) { + Module module, Void unused) { this.name = name; this.factories = factories; - this.callerRef = new WeakReference>(caller); + this.moduleRef = new WeakReference<>(module); } /** @@ -270,12 +271,12 @@ public final class LazyLoggers { // Creates the wrapped logger by invoking the SPI. Logger createLogger() { - final Class caller = callerRef.get(); - if (caller == null) { - throw new IllegalStateException("The class for which this logger" + final Module module = moduleRef.get(); + if (module == null) { + throw new IllegalStateException("The module for which this logger" + " was created has been garbage collected"); } - return this.factories.loggerSupplier.apply(name, caller); + return this.factories.loggerSupplier.apply(name, module); } /** @@ -289,8 +290,8 @@ public final class LazyLoggers { * @return A new LazyLoggerAccessor. */ public static LazyLoggerAccessor makeAccessor(String name, - LazyLoggerFactories factories, Class caller) { - return new LazyLoggerAccessor(name, factories, caller); + LazyLoggerFactories factories, Module module) { + return new LazyLoggerAccessor(name, factories, module); } } @@ -346,11 +347,11 @@ public final class LazyLoggers { // Avoid using lambda here as lazy loggers could be created early // in the bootstrap sequence... - private static final BiFunction, Logger> loggerSupplier = + private static final BiFunction loggerSupplier = new BiFunction<>() { @Override - public Logger apply(String name, Class caller) { - return LazyLoggers.getLoggerFromFinder(name, caller); + public Logger apply(String name, Module module) { + return LazyLoggers.getLoggerFromFinder(name, module); } }; @@ -367,8 +368,8 @@ public final class LazyLoggers { // logger provider until the VM has finished booting. // private static final class JdkLazyLogger extends LazyLoggerWrapper { - JdkLazyLogger(String name, Class caller) { - this(LazyLoggerAccessor.makeAccessor(name, factories, caller), + JdkLazyLogger(String name, Module module) { + this(LazyLoggerAccessor.makeAccessor(name, factories, module), (Void)null); } private JdkLazyLogger(LazyLoggerAccessor holder, Void unused) { @@ -380,16 +381,16 @@ public final class LazyLoggers { * Gets a logger from the LoggerFinder. Creates the actual concrete * logger. * @param name name of the logger - * @param caller class on behalf of which the logger is created + * @param module module on behalf of which the logger is created * @return The logger returned by the LoggerFinder. */ - static Logger getLoggerFromFinder(String name, Class caller) { + static Logger getLoggerFromFinder(String name, Module module) { final SecurityManager sm = System.getSecurityManager(); if (sm == null) { - return accessLoggerFinder().getLogger(name, caller); + return accessLoggerFinder().getLogger(name, module); } else { return AccessController.doPrivileged((PrivilegedAction) - () -> {return accessLoggerFinder().getLogger(name, caller);}, + () -> {return accessLoggerFinder().getLogger(name, module);}, null, LOGGERFINDER_PERMISSION); } } @@ -398,22 +399,22 @@ public final class LazyLoggers { * Returns a (possibly lazy) Logger for the caller. * * @param name the logger name - * @param caller The class on behalf of which the logger is created. - * If the caller is not loaded from the Boot ClassLoader, + * @param module The module on behalf of which the logger is created. + * If the module is not loaded from the Boot ClassLoader, * the LoggerFinder is accessed and the logger returned - * by {@link LoggerFinder#getLogger(java.lang.String, java.lang.Class)} + * by {@link LoggerFinder#getLogger(java.lang.String, java.lang.reflect.Module)} * is returned to the caller directly. * Otherwise, the logger returned by - * {@link #getLazyLogger(java.lang.String, java.lang.Class)} + * {@link #getLazyLogger(java.lang.String, java.lang.reflect.Module)} * is returned to the caller. * * @return a (possibly lazy) Logger instance. */ - public static final Logger getLogger(String name, Class caller) { - if (caller.getClassLoader() == null) { - return getLazyLogger(name, caller); + public static final Logger getLogger(String name, Module module) { + if (DefaultLoggerFinder.isSystem(module)) { + return getLazyLogger(name, module); } else { - return getLoggerFromFinder(name, caller); + return getLoggerFromFinder(name, module); } } @@ -423,10 +424,10 @@ public final class LazyLoggers { * returned by {@link BootstrapLogger#useLazyLoggers()}. * * @param name the logger name - * @param caller the class on behalf of which the logger is created. + * @param module the module on behalf of which the logger is created. * @return a (possibly lazy) Logger instance. */ - public static final Logger getLazyLogger(String name, Class caller) { + public static final Logger getLazyLogger(String name, Module module) { // BootstrapLogger has the logic to determine whether a LazyLogger // should be used. Usually, it is worth it only if: @@ -438,10 +439,10 @@ public final class LazyLoggers { // configuration, we're not going to delay the creation of loggers... final boolean useLazyLogger = BootstrapLogger.useLazyLoggers(); if (useLazyLogger) { - return new JdkLazyLogger(name, caller); + return new JdkLazyLogger(name, module); } else { // Directly invoke the LoggerFinder. - return getLoggerFromFinder(name, caller); + return getLoggerFromFinder(name, module); } } diff --git a/jdk/src/java.base/share/classes/sun/util/logging/PlatformLogger.java b/jdk/src/java.base/share/classes/sun/util/logging/PlatformLogger.java index 655dc96a299..e8df610c4c1 100644 --- a/jdk/src/java.base/share/classes/sun/util/logging/PlatformLogger.java +++ b/jdk/src/java.base/share/classes/sun/util/logging/PlatformLogger.java @@ -286,12 +286,15 @@ public class PlatformLogger { } if (log == null) { log = new PlatformLogger(PlatformLogger.Bridge.convert( - // We pass PlatformLogger.class rather than the actual caller + // We pass PlatformLogger.class.getModule() (java.base) + // rather than the actual module of the caller // because we want PlatformLoggers to be system loggers: we // won't need to resolve any resource bundles anyway. // Note: Many unit tests depend on the fact that - // PlatformLogger.getLoggerFromFinder is not caller sensitive. - LazyLoggers.getLazyLogger(name, PlatformLogger.class))); + // PlatformLogger.getLoggerFromFinder is not caller + // sensitive, and this strategy ensure that the tests + // still pass. + LazyLoggers.getLazyLogger(name, PlatformLogger.class.getModule()))); loggers.put(name, new WeakReference<>(log)); } return log; diff --git a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java index e15add5a4f8..6d0cc8de4d6 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java @@ -43,6 +43,8 @@ import java.util.stream.Stream; import jdk.internal.misc.JavaAWTAccess; import jdk.internal.misc.SharedSecrets; import sun.util.logging.internal.LoggingProviderImpl; +import java.lang.reflect.Module; +import static jdk.internal.logger.DefaultLoggerFinder.isSystem; /** * There is a single global LogManager object that is used to @@ -503,10 +505,16 @@ public class LogManager { // as a LogManager subclass may override the addLogger, getLogger, // readConfiguration, and other methods. Logger demandLogger(String name, String resourceBundleName, Class caller) { + final Module module = caller == null ? null : caller.getModule(); + return demandLogger(name, resourceBundleName, module); + } + + Logger demandLogger(String name, String resourceBundleName, Module module) { Logger result = getLogger(name); if (result == null) { // only allocate the new logger once - Logger newLogger = new Logger(name, resourceBundleName, caller, this, false); + Logger newLogger = new Logger(name, resourceBundleName, + module == null ? null : module, this, false); do { if (addLogger(newLogger)) { // We successfully added the new Logger that we @@ -532,9 +540,14 @@ public class LogManager { } Logger demandSystemLogger(String name, String resourceBundleName, Class caller) { + final Module module = caller == null ? null : caller.getModule(); + return demandSystemLogger(name, resourceBundleName, module); + } + + Logger demandSystemLogger(String name, String resourceBundleName, Module module) { // Add a system logger in the system context's namespace final Logger sysLogger = getSystemContext() - .demandLogger(name, resourceBundleName, caller); + .demandLogger(name, resourceBundleName, module); // Add the system logger to the LogManager's namespace if not exist // so that there is only one single logger of the given name. @@ -619,11 +632,11 @@ public class LogManager { return global; } - Logger demandLogger(String name, String resourceBundleName, Class caller) { + Logger demandLogger(String name, String resourceBundleName, Module module) { // a LogManager subclass may have its own implementation to add and // get a Logger. So delegate to the LogManager to do the work. final LogManager owner = getOwner(); - return owner.demandLogger(name, resourceBundleName, caller); + return owner.demandLogger(name, resourceBundleName, module); } @@ -907,11 +920,13 @@ public class LogManager { // one single logger of the given name. System loggers are visible // to applications unless a logger of the same name has been added. @Override - Logger demandLogger(String name, String resourceBundleName, Class caller) { + Logger demandLogger(String name, String resourceBundleName, + Module module) { Logger result = findLogger(name); if (result == null) { // only allocate the new system logger once - Logger newLogger = new Logger(name, resourceBundleName, caller, getOwner(), true); + Logger newLogger = new Logger(name, resourceBundleName, + module, getOwner(), true); do { if (addLocalLogger(newLogger)) { // We successfully added the new Logger that we @@ -2622,18 +2637,18 @@ public class LogManager { } /** - * Demands a logger on behalf of the given {@code caller}. + * Demands a logger on behalf of the given {@code module}. *

    - * If a named logger suitable for the given caller is found + * If a named logger suitable for the given module is found * returns it. - * Otherwise, creates a new logger suitable for the given caller. + * Otherwise, creates a new logger suitable for the given module. * * @param name The logger name. - * @param caller The caller on which behalf the logger is created/retrieved. - * @return A logger for the given {@code caller}. + * @param module The module on which behalf the logger is created/retrieved. + * @return A logger for the given {@code module}. * * @throws NullPointerException if {@code name} is {@code null} - * or {@code caller} is {@code null}. + * or {@code module} is {@code null}. * @throws IllegalArgumentException if {@code manager} is not the default * LogManager. * @throws SecurityException if a security manager is present and the @@ -2641,7 +2656,7 @@ public class LogManager { * {@link LoggingPermission LoggingPermission("demandLogger", null)}. */ @Override - public Logger demandLoggerFor(LogManager manager, String name, /* Module */ Class caller) { + public Logger demandLoggerFor(LogManager manager, String name, Module module) { if (manager != getLogManager()) { // having LogManager as parameter just ensures that the // caller will have initialized the LogManager before reaching @@ -2649,15 +2664,16 @@ public class LogManager { throw new IllegalArgumentException("manager"); } Objects.requireNonNull(name); + Objects.requireNonNull(module); SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(controlPermission); } - if (caller.getClassLoader() == null) { + if (isSystem(module)) { return manager.demandSystemLogger(name, - Logger.SYSTEM_LOGGER_RB_NAME, caller); + Logger.SYSTEM_LOGGER_RB_NAME, module); } else { - return manager.demandLogger(name, null, caller); + return manager.demandLogger(name, null, module); } } diff --git a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java index d8ada0c4c08..ca055b06af1 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java @@ -40,6 +40,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; +import static jdk.internal.logger.DefaultLoggerFinder.isSystem; /** * A Logger object is used to log messages for a specific @@ -379,7 +380,8 @@ public class Logger { this(name, resourceBundleName, null, LogManager.getLogManager(), false); } - Logger(String name, String resourceBundleName, Class caller, LogManager manager, boolean isSystemLogger) { + Logger(String name, String resourceBundleName, Module caller, + LogManager manager, boolean isSystemLogger) { this.manager = manager; this.isSystemLogger = isSystemLogger; setupResourceInfo(resourceBundleName, caller); @@ -387,10 +389,7 @@ public class Logger { levelValue = Level.INFO.intValue(); } - private void setCallerModuleRef(Class caller) { - Module callerModule = ((caller != null) - ? caller.getModule() - : null); + private void setCallerModuleRef(Module callerModule) { if (callerModule != null) { this.callerModuleRef = new WeakReference<>(callerModule); } @@ -618,7 +617,7 @@ public class Logger { // all loggers in the system context will default to // the system logger's resource bundle - therefore the caller won't // be needed and can be null. - Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME, null); + Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME, (Module)null); return result; } @@ -681,8 +680,10 @@ public class Logger { LogManager manager = LogManager.getLogManager(); // cleanup some Loggers that have been GC'ed manager.drainLoggerRefQueueBounded(); + final Class callerClass = Reflection.getCallerClass(); + final Module module = callerClass.getModule(); Logger result = new Logger(null, resourceBundleName, - Reflection.getCallerClass(), manager, false); + module, manager, false); result.anonymous = true; Logger root = manager.getLogger(""); result.doSetParent(root); @@ -2046,6 +2047,11 @@ public class Logger { } } + private void setupResourceInfo(String name, Class caller) { + final Module module = caller == null ? null : caller.getModule(); + setupResourceInfo(name, module); + } + // Private utility method to initialize our one entry // resource bundle name cache and the callers Module // Note: for consistency reasons, we are careful to check @@ -2053,7 +2059,7 @@ public class Logger { // resourceBundleName field. // Synchronized to prevent races in setting the fields. private synchronized void setupResourceInfo(String name, - Class callerClass) { + Module callerModule) { final LoggerBundle lb = loggerBundle; if (lb.resourceBundleName != null) { // this Logger already has a ResourceBundle @@ -2072,8 +2078,9 @@ public class Logger { return; } - setCallerModuleRef(callerClass); - if (isSystemLogger && (callerClass != null && callerClass.getClassLoader() != null)) { + setCallerModuleRef(callerModule); + + if (isSystemLogger && (callerModule != null && !isSystem(callerModule))) { checkPermission(); } diff --git a/jdk/src/java.logging/share/classes/sun/util/logging/internal/LoggingProviderImpl.java b/jdk/src/java.logging/share/classes/sun/util/logging/internal/LoggingProviderImpl.java index 4fcf40d2daa..1ccf2cf7c92 100644 --- a/jdk/src/java.logging/share/classes/sun/util/logging/internal/LoggingProviderImpl.java +++ b/jdk/src/java.logging/share/classes/sun/util/logging/internal/LoggingProviderImpl.java @@ -32,6 +32,7 @@ import java.util.ResourceBundle; import java.util.function.Supplier; import java.lang.System.LoggerFinder; import java.lang.System.Logger; +import java.lang.reflect.Module; import java.util.Objects; import java.util.logging.LogManager; import jdk.internal.logger.DefaultLoggerFinder; @@ -398,21 +399,20 @@ public final class LoggingProviderImpl extends DefaultLoggerFinder { } /** - * Creates a java.util.logging.Logger for the given caller. + * Creates a java.util.logging.Logger for the given module. * @param name the logger name. - * @param caller the caller for which the logger should be created. - * @return a Logger suitable for use in the given caller. + * @param module the module for which the logger should be created. + * @return a Logger suitable for use in the given module. */ private static java.util.logging.Logger demandJULLoggerFor(final String name, - /* Module */ - final Class caller) { + Module module) { final LogManager manager = LogManager.getLogManager(); final SecurityManager sm = System.getSecurityManager(); if (sm == null) { - return logManagerAccess.demandLoggerFor(manager, name, caller); + return logManagerAccess.demandLoggerFor(manager, name, module); } else { final PrivilegedAction pa = - () -> logManagerAccess.demandLoggerFor(manager, name, caller); + () -> logManagerAccess.demandLoggerFor(manager, name, module); return AccessController.doPrivileged(pa, null, LOGGING_CONTROL_PERMISSION); } } @@ -429,17 +429,17 @@ public final class LoggingProviderImpl extends DefaultLoggerFinder { * {@code RuntimePermission("loggerFinder")}. */ @Override - protected Logger demandLoggerFor(String name, /* Module */ Class caller) { + protected Logger demandLoggerFor(String name, Module module) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGERFINDER_PERMISSION); } - return JULWrapper.of(demandJULLoggerFor(name,caller)); + return JULWrapper.of(demandJULLoggerFor(name,module)); } public static interface LogManagerAccess { java.util.logging.Logger demandLoggerFor(LogManager manager, - String name, /* Module */ Class caller); + String name, Module module); } // Hook for tests diff --git a/jdk/test/java/lang/System/Logger/custom/CustomLoggerTest.java b/jdk/test/java/lang/System/Logger/custom/CustomLoggerTest.java index 2506905ec7c..d1653ca5f1e 100644 --- a/jdk/test/java/lang/System/Logger/custom/CustomLoggerTest.java +++ b/jdk/test/java/lang/System/Logger/custom/CustomLoggerTest.java @@ -46,6 +46,8 @@ import java.lang.System.LoggerFinder; import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.util.stream.Stream; +import java.lang.reflect.Module; +import java.security.AllPermission; /** * @test @@ -70,6 +72,12 @@ public class CustomLoggerTest { return new AtomicBoolean(false); } }; + static final ThreadLocal allowAll = new ThreadLocal() { + @Override + protected AtomicBoolean initialValue() { + return new AtomicBoolean(false); + } + }; public static class MyBundle extends ResourceBundle { @@ -241,7 +249,7 @@ public class CustomLoggerTest { } @Override - public Logger getLogger(String name, Class caller) { + public Logger getLogger(String name, Module caller) { // We should check the permission to obey the API contract, but // what happens if we don't? // This is the main difference compared with what we test in @@ -251,8 +259,13 @@ public class CustomLoggerTest { sm.checkPermission(SimplePolicy.LOGGERFINDER_PERMISSION); } - PrivilegedAction pa = () -> caller.getClassLoader(); - ClassLoader callerLoader = AccessController.doPrivileged(pa); + final boolean before = allowAll.get().getAndSet(true); + final ClassLoader callerLoader; + try { + callerLoader = caller.getClassLoader(); + } finally { + allowAll.get().set(before); + } if (callerLoader == null) { return system.computeIfAbsent(name, (n) -> new LoggerImpl(n)); } else { @@ -267,7 +280,7 @@ public class CustomLoggerTest { static void setSecurityManager() { if (System.getSecurityManager() == null) { - Policy.setPolicy(new SimplePolicy(allowControl)); + Policy.setPolicy(new SimplePolicy(allowControl, allowAll)); System.setSecurityManager(new SecurityManager()); } } @@ -284,9 +297,9 @@ public class CustomLoggerTest { BaseLoggerFinder provider = BaseLoggerFinder.class.cast(LoggerFinder.getLoggerFinder()); BaseLoggerFinder.LoggerImpl appSink = - BaseLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", CustomLoggerTest.class)); + BaseLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", CustomLoggerTest.class.getModule())); BaseLoggerFinder.LoggerImpl sysSink = - BaseLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class)); + BaseLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class.getModule())); Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> { @@ -695,34 +708,46 @@ public class CustomLoggerTest { static final RuntimePermission LOGGERFINDER_PERMISSION = new RuntimePermission("loggerFinder"); final Permissions permissions; + final Permissions controlPermissions; final Permissions allPermissions; final ThreadLocal allowControl; - public SimplePolicy(ThreadLocal allowControl) { + final ThreadLocal allowAll; + public SimplePolicy(ThreadLocal allowControl, ThreadLocal allowAll) { this.allowControl = allowControl; + this.allowAll = allowAll; permissions = new Permissions(); // these are used for configuring the test itself... + controlPermissions = new Permissions(); + controlPermissions.add(LOGGERFINDER_PERMISSION); + + // these are used for simulating a doPrivileged call from + // a class in the BCL allPermissions = new Permissions(); - allPermissions.add(LOGGERFINDER_PERMISSION); + allPermissions.add(new AllPermission()); + + } + + Permissions permissions() { + if (allowAll.get().get()) return allPermissions; + if (allowControl.get().get()) return controlPermissions; + return permissions; } @Override public boolean implies(ProtectionDomain domain, Permission permission) { - if (allowControl.get().get()) return allPermissions.implies(permission); - return permissions.implies(permission); + return permissions().implies(permission); } @Override public PermissionCollection getPermissions(CodeSource codesource) { - return new PermissionsBuilder().addAll(allowControl.get().get() - ? allPermissions : permissions).toPermissions(); + return new PermissionsBuilder().addAll(permissions()).toPermissions(); } @Override public PermissionCollection getPermissions(ProtectionDomain domain) { - return new PermissionsBuilder().addAll(allowControl.get().get() - ? allPermissions : permissions).toPermissions(); + return new PermissionsBuilder().addAll(permissions()).toPermissions(); } } } diff --git a/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinder.java b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinder.java index 30daa232248..3db7cef65f8 100644 --- a/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinder.java +++ b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinder.java @@ -25,13 +25,14 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.lang.System.LoggerFinder; import java.lang.System.Logger; +import java.lang.reflect.Module; public class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder { static final RuntimePermission LOGGERFINDER_PERMISSION = new RuntimePermission("loggerFinder"); @Override - public Logger getLogger(String name, Class caller) { + public Logger getLogger(String name, Module caller) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGERFINDER_PERMISSION); diff --git a/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinderTest.java b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinderTest.java index 2cb57d78559..b3805919e53 100644 --- a/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinderTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinderTest.java @@ -182,8 +182,8 @@ public class BaseLoggerFinderTest { TestLoggerFinder.LoggerImpl appLogger1 = null; try { appLogger1 = - TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerFinderTest.class)); - loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", BaseLoggerFinderTest.class)"); + TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerFinderTest.class.getModule())); + loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", BaseLoggerFinderTest.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a logger without permission"); } @@ -199,8 +199,8 @@ public class BaseLoggerFinderTest { allowControl.get().set(true); try { appLogger1 = - TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerFinderTest.class)); - loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", BaseLoggerFinderTest.class)"); + TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerFinderTest.class.getModule())); + loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", BaseLoggerFinderTest.class.getModule())"); } finally { allowControl.get().set(old); } @@ -208,8 +208,8 @@ public class BaseLoggerFinderTest { TestLoggerFinder.LoggerImpl sysLogger1 = null; try { - sysLogger1 = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class)); - loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class)"); + sysLogger1 = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class.getModule())); + loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } @@ -224,8 +224,8 @@ public class BaseLoggerFinderTest { final boolean old = allowControl.get().get(); allowControl.get().set(true); try { - sysLogger1 = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class)); - loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class)"); + sysLogger1 = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class.getModule())); + loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class.getModule())"); } finally { allowControl.get().set(old); } @@ -254,8 +254,8 @@ public class BaseLoggerFinderTest { // callers and non system callers Logger appLogger2 = null; try { - appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, BaseLoggerFinderTest.class); - loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, BaseLoggerFinderTest.class)"); + appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, BaseLoggerFinderTest.class.getModule()); + loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, BaseLoggerFinderTest.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a logger without permission"); } @@ -270,8 +270,8 @@ public class BaseLoggerFinderTest { final boolean old = allowControl.get().get(); allowControl.get().set(true); try { - appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, BaseLoggerFinderTest.class); - loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, BaseLoggerFinderTest.class)"); + appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, BaseLoggerFinderTest.class.getModule()); + loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, BaseLoggerFinderTest.class.getModule())"); } finally { allowControl.get().set(old); } @@ -279,8 +279,8 @@ public class BaseLoggerFinderTest { Logger sysLogger2 = null; try { - sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class); - loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class)"); + sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class.getModule()); + loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } @@ -295,8 +295,8 @@ public class BaseLoggerFinderTest { final boolean old = allowControl.get().get(); allowControl.get().set(true); try { - sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class); - loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class))"); + sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class.getModule()); + loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class.getModule()))"); } finally { allowControl.get().set(old); } diff --git a/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/TestLoggerFinder.java b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/TestLoggerFinder.java index 716f8b8faec..cb86e513f90 100644 --- a/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/TestLoggerFinder.java +++ b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/TestLoggerFinder.java @@ -30,6 +30,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; import java.lang.System.Logger; +import java.lang.reflect.Module; /** * What our test provider needs to implement. @@ -176,6 +177,6 @@ public interface TestLoggerFinder { } } - public Logger getLogger(String name, Class caller); - public Logger getLocalizedLogger(String name, ResourceBundle bundle, Class caller); + public Logger getLogger(String name, Module caller); + public Logger getLocalizedLogger(String name, ResourceBundle bundle, Module caller); } diff --git a/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/DefaultLoggerFinderTest.java b/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/DefaultLoggerFinderTest.java index 50c789b5d60..43150eb0f00 100644 --- a/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/DefaultLoggerFinderTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/DefaultLoggerFinderTest.java @@ -364,8 +364,8 @@ public class DefaultLoggerFinderTest { Logger appLogger1 = null; try { - appLogger1 = provider.getLogger("foo", DefaultLoggerFinderTest.class); - loggerDescMap.put(appLogger1, "provider.getApplicationLogger(\"foo\")"); + appLogger1 = provider.getLogger("foo", DefaultLoggerFinderTest.class.getModule()); + loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", DefaultLoggerFinderTest.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a logger without permission"); } @@ -380,8 +380,8 @@ public class DefaultLoggerFinderTest { boolean old = allowControl.get().get(); allowControl.get().set(true); try { - appLogger1 =provider.getLogger("foo", DefaultLoggerFinderTest.class); - loggerDescMap.put(appLogger1, "provider.getApplicationLogger(\"foo\")"); + appLogger1 =provider.getLogger("foo", DefaultLoggerFinderTest.class.getModule()); + loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", DefaultLoggerFinderTest.class.getModule())"); } finally { allowControl.get().set(old); } @@ -389,8 +389,8 @@ public class DefaultLoggerFinderTest { Logger sysLogger1 = null; try { - sysLogger1 = provider.getLogger("foo", Thread.class); - loggerDescMap.put(sysLogger1, "provider.getSystemLogger(\"foo\")"); + sysLogger1 = provider.getLogger("foo", Thread.class.getModule()); + loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } @@ -405,8 +405,8 @@ public class DefaultLoggerFinderTest { boolean old = allowControl.get().get(); allowControl.get().set(true); try { - sysLogger1 = provider.getLogger("foo", Thread.class); - loggerDescMap.put(sysLogger1, "provider.getSystemLogger(\"foo\")"); + sysLogger1 = provider.getLogger("foo", Thread.class.getModule()); + loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class.getModule())"); } finally { allowControl.get().set(old); } @@ -417,8 +417,8 @@ public class DefaultLoggerFinderTest { Logger appLogger2 = null; try { - appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, DefaultLoggerFinderTest.class); - loggerDescMap.put(appLogger2, "provider.getLocalizedApplicationLogger(\"foo\", loggerBundle)"); + appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, DefaultLoggerFinderTest.class.getModule()); + loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, DefaultLoggerFinderTest.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a logger without permission"); } @@ -433,8 +433,8 @@ public class DefaultLoggerFinderTest { boolean old = allowControl.get().get(); allowControl.get().set(true); try { - appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, DefaultLoggerFinderTest.class); - loggerDescMap.put(appLogger2, "provider.getLocalizedApplicationLogger(\"foo\", loggerBundle)"); + appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, DefaultLoggerFinderTest.class.getModule()); + loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, DefaultLoggerFinderTest.class.getModule())"); } finally { allowControl.get().set(old); } @@ -442,8 +442,8 @@ public class DefaultLoggerFinderTest { Logger sysLogger2 = null; try { - sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class); - loggerDescMap.put(sysLogger2, "provider.getLocalizedSystemLogger(\"foo\", loggerBundle)"); + sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class.getModule()); + loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } @@ -458,8 +458,8 @@ public class DefaultLoggerFinderTest { boolean old = allowControl.get().get(); allowControl.get().set(true); try { - sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class); - loggerDescMap.put(sysLogger2, "provider.getLocalizedSystemLogger(\"foo\", loggerBundle)"); + sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class.getModule()); + loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class.getModule())"); } finally { allowControl.get().set(old); } diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/BaseDefaultLoggerFinderTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/BaseDefaultLoggerFinderTest.java index ddf1be7731c..ab80d0f8bc6 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/BaseDefaultLoggerFinderTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/BaseDefaultLoggerFinderTest.java @@ -55,6 +55,7 @@ import java.util.function.Function; import jdk.internal.logger.DefaultLoggerFinder; import jdk.internal.logger.SimpleConsoleLogger; import sun.util.logging.PlatformLogger; +import java.lang.reflect.Module; /** * @test @@ -112,10 +113,10 @@ public class BaseDefaultLoggerFinderTest { public final static AtomicLong sequencer = new AtomicLong(); - public Logger getLogger(String name, Class caller); - public Logger getLocalizedLogger(String name, ResourceBundle bundle, Class caller); - void setLevel(Logger logger, Level level, Class caller); - void setLevel(Logger logger, PlatformLogger.Level level, Class caller); + public Logger getLogger(String name, Module caller); + public Logger getLocalizedLogger(String name, ResourceBundle bundle, Module caller); + void setLevel(Logger logger, Level level, Module caller); + void setLevel(Logger logger, PlatformLogger.Level level, Module caller); PlatformLogger.Bridge asPlatformLoggerBridge(Logger logger); } @@ -130,7 +131,7 @@ public class BaseDefaultLoggerFinderTest { } @Override - public void setLevel(Logger logger, Level level, Class caller) { + public void setLevel(Logger logger, Level level, Module caller) { PrivilegedAction pa = () -> { setLevel(logger, PlatformLogger.toPlatformLevel(level), caller); return null; @@ -139,7 +140,7 @@ public class BaseDefaultLoggerFinderTest { } @Override - public void setLevel(Logger logger, PlatformLogger.Level level, Class caller) { + public void setLevel(Logger logger, PlatformLogger.Level level, Module caller) { PrivilegedAction pa = () -> demandLoggerFor(logger.getName(), caller); Logger impl = AccessController.doPrivileged(pa); SimpleConsoleLogger.class.cast(impl) @@ -606,11 +607,12 @@ public class BaseDefaultLoggerFinderTest { String name, ResourceBundle loggerBundle, Logger logger, - Class caller) { + Class callerClass) { System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger +"]"); AtomicLong sequencer = TestLoggerFinder.sequencer; + Module caller = callerClass.getModule(); Foo foo = new Foo(); String fooMsg = foo.toString(); for (Level loggerLevel : Level.values()) { diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/BaseLoggerBridgeTest/BaseLoggerBridgeTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/BaseLoggerBridgeTest/BaseLoggerBridgeTest.java index 5319f0e5fbf..d28481c305f 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/BaseLoggerBridgeTest/BaseLoggerBridgeTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseLoggerBridgeTest/BaseLoggerBridgeTest.java @@ -47,6 +47,7 @@ import java.lang.System.LoggerFinder; import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.util.stream.Stream; +import java.lang.reflect.Module; /** * @test @@ -209,8 +210,6 @@ public class BaseLoggerBridgeTest { return Arrays.deepToString(toArray(false)); } - - @Override public boolean equals(Object obj) { return obj instanceof LogEvent @@ -342,15 +341,15 @@ public class BaseLoggerBridgeTest { } - public Logger getLogger(String name, Class caller); - public Logger getLocalizedLogger(String name, ResourceBundle bundle, Class caller); + public Logger getLogger(String name, Module caller); + public Logger getLocalizedLogger(String name, ResourceBundle bundle, Module caller); } public static class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder { static final RuntimePermission LOGGERFINDER_PERMISSION = new RuntimePermission("loggerFinder"); @Override - public Logger getLogger(String name, Class caller) { + public Logger getLogger(String name, Module caller) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGERFINDER_PERMISSION); @@ -375,7 +374,7 @@ public class BaseLoggerBridgeTest { } } - static Logger getLogger(String name, Class caller) { + static Logger getLogger(String name, Module caller) { boolean old = allowAll.get().get(); allowAccess.get().set(true); try { @@ -465,7 +464,7 @@ public class BaseLoggerBridgeTest { TestLoggerFinder.LoggerImpl appSink = null; try { - appSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerBridgeTest.class)); + appSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerBridgeTest.class.getModule())); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } @@ -480,7 +479,7 @@ public class BaseLoggerBridgeTest { boolean old = allowControl.get().get(); allowControl.get().set(true); try { - appSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerBridgeTest.class)); + appSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerBridgeTest.class.getModule())); } finally { allowControl.get().set(old); } @@ -489,7 +488,7 @@ public class BaseLoggerBridgeTest { TestLoggerFinder.LoggerImpl sysSink = null; try { - sysSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class)); + sysSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class.getModule())); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } @@ -527,13 +526,13 @@ public class BaseLoggerBridgeTest { Logger sysLogger1 = null; try { - sysLogger1 = getLogger("foo", Thread.class); + sysLogger1 = getLogger("foo", Thread.class.getModule()); loggerDescMap.put(sysLogger1, - "jdk.internal.logger.LazyLoggers.getLogger(\"foo\", Thread.class)"); + "jdk.internal.logger.LazyLoggers.getLogger(\"foo\", Thread.class.getModule())"); if (!hasRequiredPermissions) { // check that the provider would have thrown an exception - provider.getLogger("foo", Thread.class); + provider.getLogger("foo", Thread.class.getModule()); throw new RuntimeException("Managed to obtain a system logger without permission"); } } catch (AccessControlException acx) { @@ -572,8 +571,8 @@ public class BaseLoggerBridgeTest { Logger sysLogger2 = null; try { - sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class); - loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class)"); + sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class.getModule()); + loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/BasePlatformLoggerTest/BasePlatformLoggerTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/BasePlatformLoggerTest/BasePlatformLoggerTest.java index da8c2d73b16..a9e441f9d7c 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/BasePlatformLoggerTest/BasePlatformLoggerTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BasePlatformLoggerTest/BasePlatformLoggerTest.java @@ -47,6 +47,7 @@ import java.lang.System.Logger.Level; import java.security.AccessControlException; import java.util.stream.Stream; import sun.util.logging.PlatformLogger; +import java.lang.reflect.Module; /** * @test @@ -327,12 +328,12 @@ public class BasePlatformLoggerTest { } } - public Logger getLogger(String name, Class caller); + public Logger getLogger(String name, Module caller); } public static class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder { @Override - public Logger getLogger(String name, Class caller) { + public Logger getLogger(String name, Module caller) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGERFINDER_PERMISSION); @@ -433,7 +434,7 @@ public class BasePlatformLoggerTest { try { allowControl.get().set(true); appSink = TestLoggerFinder.LoggerImpl.class.cast( - provider.getLogger("foo", BasePlatformLoggerTest.class)); + provider.getLogger("foo", BasePlatformLoggerTest.class.getModule())); } finally { allowControl.get().set(before); } @@ -442,7 +443,8 @@ public class BasePlatformLoggerTest { before = allowControl.get().get(); try { allowControl.get().set(true); - sysSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class)); + sysSink = TestLoggerFinder.LoggerImpl.class.cast( + provider.getLogger("foo", Thread.class.getModule())); } finally { allowControl.get().set(before); } diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java index 7c62eb9a763..bedd6117ae8 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java @@ -30,7 +30,7 @@ import java.util.Enumeration; import java.util.List; import java.util.ResourceBundle; import java.util.Set; - +import java.lang.reflect.Module; import jdk.internal.logger.BootstrapLogger; import jdk.internal.logger.LazyLoggers; @@ -69,7 +69,7 @@ public class BootstrapLoggerAPIsTest { } final Logger LOGGER = - LazyLoggers.getLogger("foo.bar", Thread.class); + LazyLoggers.getLogger("foo.bar", Thread.class.getModule()); final sun.util.logging.PlatformLogger.Level PLATFORM_LEVEL = sun.util.logging.PlatformLogger.Level.SEVERE; final MyResources BUNDLE = new MyResources(); diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java index 033a7d97315..e2f6d4b009d 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java @@ -43,6 +43,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.logger.BootstrapLogger; import jdk.internal.logger.LazyLoggers; +import java.lang.reflect.Module; /* * @test @@ -105,7 +106,7 @@ public class BootstrapLoggerTest { if (BootstrapLogger.isBooted()) { throw new RuntimeException("VM should not be booted!"); } - Logger logger = LazyLoggers.getLogger("foo.bar", Thread.class); + Logger logger = LazyLoggers.getLogger("foo.bar", Thread.class.getModule()); if (test != TestCase.NO_SECURITY) { LogStream.err.println("Setting security manager"); @@ -261,7 +262,7 @@ public class BootstrapLoggerTest { SimplePolicy.allowAll.set(Boolean.TRUE); try { bazbaz = java.lang.System.LoggerFinder - .getLoggerFinder().getLogger("foo.bar.baz.baz", BootstrapLoggerTest.class); + .getLoggerFinder().getLogger("foo.bar.baz.baz", BootstrapLoggerTest.class.getModule()); } finally { SimplePolicy.allowAll.set(Boolean.FALSE); } diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/LoggerBridgeTest/LoggerBridgeTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerBridgeTest/LoggerBridgeTest.java index c3f5e98d39c..be5ad125518 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/LoggerBridgeTest/LoggerBridgeTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerBridgeTest/LoggerBridgeTest.java @@ -51,6 +51,7 @@ import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.util.stream.Stream; import sun.util.logging.PlatformLogger; +import java.lang.reflect.Module; /** * @test @@ -164,6 +165,7 @@ public class LoggerBridgeTest { null, null, level, bundle, key, thrown, params); } + public static LogEvent of(long sequenceNumber, boolean isLoggable, String name, sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, @@ -231,7 +233,7 @@ public class LoggerBridgeTest { try { // Preload classes before the security manager is on. providerClass = ClassLoader.getSystemClassLoader().loadClass("LoggerBridgeTest$LogProducerFinder"); - ((LoggerFinder)providerClass.newInstance()).getLogger("foo", providerClass); + ((LoggerFinder)providerClass.newInstance()).getLogger("foo", providerClass.getModule()); } catch (Exception ex) { throw new ExceptionInInitializerError(ex); } @@ -415,7 +417,7 @@ public class LoggerBridgeTest { } @Override - public Logger getLogger(String name, Class caller) { + public Logger getLogger(String name, Module caller) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGERFINDER_PERMISSION); @@ -430,6 +432,15 @@ public class LoggerBridgeTest { } } + static ClassLoader getClassLoader(Module m) { + final boolean before = allowAll.get().getAndSet(true); + try { + return m.getClassLoader(); + } finally { + allowAll.get().set(before); + } + } + static final sun.util.logging.PlatformLogger.Level[] julLevels = { sun.util.logging.PlatformLogger.Level.ALL, sun.util.logging.PlatformLogger.Level.FINEST, @@ -497,14 +508,14 @@ public class LoggerBridgeTest { try { Class bridgeClass = Class.forName("jdk.internal.logger.LazyLoggers"); lazyGetLogger = bridgeClass.getDeclaredMethod("getLogger", - String.class, Class.class); + String.class, Module.class); lazyGetLogger.setAccessible(true); } catch (Throwable ex) { throw new ExceptionInInitializerError(ex); } } - static Logger getLogger(LoggerFinder provider, String name, Class caller) { + static Logger getLogger(LoggerFinder provider, String name, Module caller) { Logger logger; try { logger = Logger.class.cast(lazyGetLogger.invoke(null, name, caller)); @@ -522,14 +533,14 @@ public class LoggerBridgeTest { // The method above does not throw exception... // call the provider here to verify that an exception would have // been thrown by the provider. - if (logger != null && caller == Thread.class) { + if (logger != null && caller == Thread.class.getModule()) { Logger log = provider.getLogger(name, caller); } return logger; } - static Logger getLogger(LoggerFinder provider, String name, ResourceBundle bundle, Class caller) { - if (caller.getClassLoader() != null) { + static Logger getLogger(LoggerFinder provider, String name, ResourceBundle bundle, Module caller) { + if (getClassLoader(caller) != null) { return System.getLogger(name,bundle); } else { return provider.getLocalizedLogger(name, bundle, caller); @@ -614,12 +625,12 @@ public class LoggerBridgeTest { Logger appLogger1 = System.getLogger("foo"); - loggerDescMap.put(appLogger1, "LogProducer.getApplicationLogger(\"foo\")"); + loggerDescMap.put(appLogger1, "System.getLogger(\"foo\")"); Logger sysLogger1 = null; try { - sysLogger1 = getLogger(provider, "foo", Thread.class); - loggerDescMap.put(sysLogger1, "LogProducer.getSystemLogger(\"foo\")"); + sysLogger1 = getLogger(provider, "foo", Thread.class.getModule()); + loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } @@ -636,12 +647,12 @@ public class LoggerBridgeTest { Logger appLogger2 = System.getLogger("foo", loggerBundle); - loggerDescMap.put(appLogger2, "LogProducer.getApplicationLogger(\"foo\", loggerBundle)"); + loggerDescMap.put(appLogger2, "System.getLogger(\"foo\", loggerBundle)"); Logger sysLogger2 = null; try { - sysLogger2 = getLogger(provider, "foo", loggerBundle, Thread.class); - loggerDescMap.put(sysLogger2, "provider.getSystemLogger(\"foo\", loggerBundle)"); + sysLogger2 = getLogger(provider, "foo", loggerBundle, Thread.class.getModule()); + loggerDescMap.put(sysLogger2, "provider.getLogger(\"foo\", loggerBundle, Thread.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } @@ -671,9 +682,9 @@ public class LoggerBridgeTest { allowControl.get().set(true); try { appSink = LogProducerFinder.LoggerImpl.class.cast( - provider.getLogger("foo", LoggerBridgeTest.class)); + provider.getLogger("foo", LoggerBridgeTest.class.getModule())); sysSink = LogProducerFinder.LoggerImpl.class.cast( - provider.getLogger("foo", Thread.class)); + provider.getLogger("foo", Thread.class.getModule())); } finally { allowControl.get().set(old); } diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java index 98418430a71..6343a90312c 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java @@ -53,6 +53,7 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.concurrent.atomic.AtomicReference; import jdk.internal.logger.SimpleConsoleLogger; +import java.lang.reflect.Module; /** * @test @@ -166,8 +167,8 @@ public class LoggerFinderLoaderTest { } - public Logger getLogger(String name, Class caller); - public Logger getLocalizedLogger(String name, ResourceBundle bundle, Class caller); + public Logger getLogger(String name, Module caller); + public Logger getLocalizedLogger(String name, ResourceBundle bundle, Module caller); } public static class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder { @@ -187,7 +188,7 @@ public class LoggerFinderLoaderTest { @Override - public Logger getLogger(String name, Class caller) { + public Logger getLogger(String name, Module caller) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGERFINDER_PERMISSION); @@ -210,7 +211,7 @@ public class LoggerFinderLoaderTest { throw new ServiceConfigurationError("Should not come here"); } @Override - public Logger getLogger(String name, Class caller) { + public Logger getLogger(String name, Module caller) { throw new ServiceConfigurationError("Should not come here"); } } diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/PlatformLoggerBridgeTest/PlatformLoggerBridgeTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/PlatformLoggerBridgeTest/PlatformLoggerBridgeTest.java index 1300c9b2ecd..9576e17bed6 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/PlatformLoggerBridgeTest/PlatformLoggerBridgeTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/PlatformLoggerBridgeTest/PlatformLoggerBridgeTest.java @@ -49,6 +49,7 @@ import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.util.stream.Stream; import sun.util.logging.PlatformLogger; +import java.lang.reflect.Module; /** * @test @@ -94,7 +95,7 @@ public class PlatformLoggerBridgeTest { try { // Preload classes before the security manager is on. providerClass = ClassLoader.getSystemClassLoader().loadClass("PlatformLoggerBridgeTest$LogProducerFinder"); - ((LoggerFinder)providerClass.newInstance()).getLogger("foo", providerClass); + ((LoggerFinder)providerClass.newInstance()).getLogger("foo", providerClass.getModule()); } catch (Exception ex) { throw new ExceptionInInitializerError(ex); } @@ -415,7 +416,7 @@ public class PlatformLoggerBridgeTest { } @Override - public Logger getLogger(String name, Class caller) { + public Logger getLogger(String name, Module caller) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGERFINDER_PERMISSION); @@ -598,7 +599,7 @@ public class PlatformLoggerBridgeTest { allowControl.get().set(true); try { sysSink = LogProducerFinder.LoggerImpl.class.cast( - provider.getLogger("foo", Thread.class)); + provider.getLogger("foo", Thread.class.getModule())); } finally { allowControl.get().set(old); } diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/api/LoggerFinderAPITest.java b/jdk/test/java/lang/System/LoggerFinder/internal/api/LoggerFinderAPITest.java index e3752b5721c..572695458f1 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/api/LoggerFinderAPITest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/api/LoggerFinderAPITest.java @@ -469,12 +469,12 @@ public class LoggerFinderAPITest { errors.append(test.testGetLoggerOverriddenOnSpi()); java.lang.System.Logger julLogger = java.lang.System.LoggerFinder.getLoggerFinder() - .getLogger("foo", LoggerFinderAPITest.class); + .getLogger("foo", LoggerFinderAPITest.class.getModule()); errors.append(test.testDefaultJULLogger(julLogger)); if (errors.length() > 0) throw new RuntimeException(errors.toString()); java.lang.System.Logger julSystemLogger = java.lang.System.LoggerFinder.getLoggerFinder() - .getLogger("bar", Thread.class); + .getLogger("bar", Thread.class.getModule()); errors.append(test.testDefaultJULLogger(julSystemLogger)); if (errors.length() > 0) throw new RuntimeException(errors.toString()); java.lang.System.Logger julLocalizedLogger = @@ -482,7 +482,7 @@ public class LoggerFinderAPITest { System.getLogger("baz", bundleLocalized); java.lang.System.Logger julLocalizedSystemLogger = java.lang.System.LoggerFinder.getLoggerFinder() - .getLocalizedLogger("oof", bundleLocalized, Thread.class); + .getLocalizedLogger("oof", bundleLocalized, Thread.class.getModule()); final String error = errors.toString(); if (!error.isEmpty()) throw new RuntimeException(error); for (java.lang.System.Logger logger : new java.lang.System.Logger[] { diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java index 226f2f7cf30..eb3f07c3ec3 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java @@ -77,6 +77,7 @@ import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.Logger; import sun.util.logging.internal.LoggingProviderImpl; +import java.lang.reflect.Module; /** * @author danielfuchs @@ -1506,7 +1507,7 @@ public class LoggerFinderBackendTest { Logger getBackendLogger(String name) { if (isSystem) { return LoggingProviderImpl.getLogManagerAccess().demandLoggerFor( - LogManager.getLogManager(), name, Thread.class); + LogManager.getLogManager(), name, Thread.class.getModule()); } else { return Logger.getLogger(name); } @@ -1699,7 +1700,7 @@ public class LoggerFinderBackendTest { Collections.synchronizedMap(new HashMap<>()); @Override - public java.lang.System.Logger getLogger(String name, Class caller) { + public java.lang.System.Logger getLogger(String name, Module caller) { ClassLoader callerLoader = caller.getClassLoader(); if (callerLoader == null) { systemLoggers.putIfAbsent(name, new CustomLogger(name)); @@ -1827,8 +1828,8 @@ public class LoggerFinderBackendTest { public void setLevel(java.lang.System.Logger logger, Level level) { final CustomLoggerFinder.CustomLogger l = (CustomLoggerFinder.CustomLogger) - (isSystem ? provider.getLogger(logger.getName(), Thread.class) : - provider.getLogger(logger.getName(), LoggerFinderBackendTest.class)); + (isSystem ? provider.getLogger(logger.getName(), Thread.class.getModule()) : + provider.getLogger(logger.getName(), LoggerFinderBackendTest.class.getModule())); l.setLevel(provider.fromJul(level)); } @Override @@ -1840,8 +1841,8 @@ public class LoggerFinderBackendTest { CustomLoggerFinder.CustomLevel getLevel(java.lang.System.Logger logger) { final CustomLoggerFinder.CustomLogger l = (CustomLoggerFinder.CustomLogger) - (isSystem ? provider.getLogger(logger.getName(), Thread.class) : - provider.getLogger(logger.getName(), LoggerFinderBackendTest.class)); + (isSystem ? provider.getLogger(logger.getName(), Thread.class.getModule()) : + provider.getLogger(logger.getName(), LoggerFinderBackendTest.class.getModule())); return l.level; } @@ -1962,7 +1963,7 @@ public class LoggerFinderBackendTest { try { Class lazyLoggers = jdk.internal.logger.LazyLoggers.class; getLazyLogger = lazyLoggers.getMethod("getLazyLogger", - String.class, Class.class); + String.class, Module.class); getLazyLogger.setAccessible(true); Class loggerFinderLoader = Class.forName("java.lang.System$LoggerFinder"); @@ -1973,7 +1974,7 @@ public class LoggerFinderBackendTest { } } - static java.lang.System.Logger getSystemLogger(String name, Class caller) throws Exception { + static java.lang.System.Logger getSystemLogger(String name, Module caller) throws Exception { try { return java.lang.System.Logger.class.cast(getLazyLogger.invoke(null, name, caller)); } catch (InvocationTargetException x) { @@ -1986,7 +1987,7 @@ public class LoggerFinderBackendTest { } } static java.lang.System.Logger getSystemLogger(String name, - ResourceBundle bundle, Class caller) throws Exception { + ResourceBundle bundle, Module caller) throws Exception { try { LoggerFinder provider = LoggerFinder.class.cast(accessLoggerFinder.invoke(null)); return provider.getLocalizedLogger(name, bundle, caller); @@ -2047,14 +2048,14 @@ public class LoggerFinderBackendTest { final BackendTester tester = factory.createBackendTester(false); final java.lang.System.Logger logger = java.lang.System.LoggerFinder.getLoggerFinder() - .getLogger("foo", LoggerFinderBackendTest.class); + .getLogger("foo", LoggerFinderBackendTest.class.getModule()); testLogger(tester, logger, nb); // Test a simple system logger with JUL backend final java.lang.System.Logger system = java.lang.System.LoggerFinder.getLoggerFinder() - .getLogger("bar", Thread.class); + .getLogger("bar", Thread.class.getModule()); final BackendTester systemTester = factory.createBackendTester(true); testLogger(systemTester, system, nb); @@ -2062,7 +2063,7 @@ public class LoggerFinderBackendTest { // JUL backend final java.lang.System.Logger noBundleLogger = java.lang.System.LoggerFinder.getLoggerFinder() - .getLocalizedLogger("baz", null, LoggerFinderBackendTest.class); + .getLocalizedLogger("baz", null, LoggerFinderBackendTest.class.getModule()); final BackendTester noBundleTester = factory.createBackendTester(false, spiLoggerClass); testLogger(noBundleTester, noBundleLogger, nb); @@ -2071,7 +2072,7 @@ public class LoggerFinderBackendTest { // backend final java.lang.System.Logger noBundleSysLogger = java.lang.System.LoggerFinder.getLoggerFinder() - .getLocalizedLogger("oof", null, Thread.class); + .getLocalizedLogger("oof", null, Thread.class.getModule()); final BackendTester noBundleSysTester = factory.createBackendTester(true, spiLoggerClass); testLogger(noBundleSysTester, noBundleSysLogger, nb); @@ -2085,14 +2086,14 @@ public class LoggerFinderBackendTest { System.out.println("System.Loggers.getLogger(\"baz\", null): got expected " + x); } final java.lang.System.Logger noBundleExtensionLogger = - getSystemLogger("baz", null, LoggerFinderBackendTest.class); + getSystemLogger("baz", null, LoggerFinderBackendTest.class.getModule()); final BackendTester noBundleExtensionTester = factory.createBackendTester(false, jdkLoggerClass); testLogger(noBundleExtensionTester, noBundleExtensionLogger, nb); // Test a simple system logger with JUL backend final java.lang.System.Logger sysExtensionLogger = - getSystemLogger("oof", Thread.class); + getSystemLogger("oof", Thread.class.getModule()); final BackendTester sysExtensionTester = factory.createBackendTester(true, jdkLoggerClass); testLogger(sysExtensionTester, sysExtensionLogger, nb); @@ -2100,7 +2101,7 @@ public class LoggerFinderBackendTest { // Test a localized system logger with null resource bundle and JUL // backend final java.lang.System.Logger noBundleSysExtensionLogger = - getSystemLogger("oof", null, Thread.class); + getSystemLogger("oof", null, Thread.class.getModule()); final BackendTester noBundleSysExtensionTester = factory.createBackendTester(true, jdkLoggerClass); testLogger(noBundleSysExtensionTester, noBundleSysExtensionLogger, nb); @@ -2127,7 +2128,7 @@ public class LoggerFinderBackendTest { ResourceBundle.getBundle(ResourceBundeLocalized.class.getName()); final java.lang.System.Logger bundleLogger = java.lang.System.LoggerFinder.getLoggerFinder() - .getLocalizedLogger("toto", bundle, LoggerFinderBackendTest.class); + .getLocalizedLogger("toto", bundle, LoggerFinderBackendTest.class.getModule()); final BackendTester bundleTester = factory.createBackendTester(false, spiLoggerClass, bundle); testLogger(bundleTester, bundleLogger, nb); @@ -2135,7 +2136,7 @@ public class LoggerFinderBackendTest { // Test a localized system logger with resource bundle and JUL backend final java.lang.System.Logger bundleSysLogger = java.lang.System.LoggerFinder.getLoggerFinder() - .getLocalizedLogger("titi", bundle, Thread.class); + .getLocalizedLogger("titi", bundle, Thread.class.getModule()); final BackendTester bundleSysTester = factory.createBackendTester(true, spiLoggerClass, bundle); testLogger(bundleSysTester, bundleSysLogger, nb); @@ -2151,7 +2152,7 @@ public class LoggerFinderBackendTest { // Test a localized Jdk system logger with resource bundle and JUL // backend final java.lang.System.Logger bundleExtensionSysLogger = - getSystemLogger("titu", bundle, Thread.class); + getSystemLogger("titu", bundle, Thread.class.getModule()); final BackendTester bundleExtensionSysTester = factory.createBackendTester(true, jdkLoggerClass, bundle); testLogger(bundleExtensionSysTester, bundleExtensionSysLogger, nb); diff --git a/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java index 6f15819fcd2..7118101cada 100644 --- a/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java @@ -48,6 +48,7 @@ import java.lang.System.LoggerFinder; import java.lang.System.Logger; import java.util.stream.Stream; import sun.util.logging.internal.LoggingProviderImpl; +import java.lang.reflect.Module; /** * @test @@ -246,7 +247,7 @@ public class DefaultLoggerBridgeTest { } } - static Logger getLogger(String name, Class caller) { + static Logger getLogger(String name, Module caller) { boolean old = allowAccess.get().get(); allowAccess.get().set(true); try { @@ -311,8 +312,8 @@ public class DefaultLoggerBridgeTest { ResourceBundle.getBundle(MyLoggerBundle.class.getName()); final Map loggerDescMap = new HashMap<>(); - Logger sysLogger1a = getLogger("foo", Thread.class); - loggerDescMap.put(sysLogger1a, "jdk.internal.logger.LazyLoggers.getLogger(\"foo\", Thread.class)"); + Logger sysLogger1a = getLogger("foo", Thread.class.getModule()); + loggerDescMap.put(sysLogger1a, "jdk.internal.logger.LazyLoggers.getLogger(\"foo\", Thread.class.getModule())"); Logger appLogger1 = System.getLogger("foo"); loggerDescMap.put(appLogger1, "System.getLogger(\"foo\")"); @@ -341,9 +342,9 @@ public class DefaultLoggerBridgeTest { Logger sysLogger1b = null; try { - sysLogger1b = provider.getLogger("foo", Thread.class); + sysLogger1b = provider.getLogger("foo", Thread.class.getModule()); if (sysLogger1b != sysLogger1a) { - loggerDescMap.put(sysLogger1b, "provider.getLogger(\"foo\", Thread.class)"); + loggerDescMap.put(sysLogger1b, "provider.getLogger(\"foo\", Thread.class.getModule())"); } if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); @@ -367,8 +368,8 @@ public class DefaultLoggerBridgeTest { Logger sysLogger2 = null; try { - sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class); - loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class)"); + sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class.getModule()); + loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class.getModule())"); if (!hasRequiredPermissions) { throw new RuntimeException("Managed to obtain a system logger without permission"); } @@ -396,9 +397,9 @@ public class DefaultLoggerBridgeTest { allowAll.get().set(true); try { sysSink = LoggingProviderImpl.getLogManagerAccess().demandLoggerFor( - LogManager.getLogManager(), "foo", Thread.class); + LogManager.getLogManager(), "foo", Thread.class.getModule()); appSink = LoggingProviderImpl.getLogManagerAccess().demandLoggerFor( - LogManager.getLogManager(), "foo", DefaultLoggerBridgeTest.class); + LogManager.getLogManager(), "foo", DefaultLoggerBridgeTest.class.getModule()); if (appSink == sysSink) { throw new RuntimeException("identical backend loggers"); } diff --git a/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultPlatformLoggerTest/DefaultPlatformLoggerTest.java b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultPlatformLoggerTest/DefaultPlatformLoggerTest.java index 2eb64d0743d..99b7ee38b2a 100644 --- a/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultPlatformLoggerTest/DefaultPlatformLoggerTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultPlatformLoggerTest/DefaultPlatformLoggerTest.java @@ -44,6 +44,7 @@ import java.util.logging.LogRecord; import java.lang.System.LoggerFinder; import sun.util.logging.PlatformLogger; import sun.util.logging.internal.LoggingProviderImpl; +import java.lang.reflect.Module; /** * @test @@ -244,9 +245,9 @@ public class DefaultPlatformLoggerTest { LoggerFinder provider = LoggerFinder.getLoggerFinder(); java.util.logging.Logger appSink = LoggingProviderImpl.getLogManagerAccess() .demandLoggerFor(LogManager.getLogManager(), "foo", - DefaultPlatformLoggerTest.class); + DefaultPlatformLoggerTest.class.getModule()); java.util.logging.Logger sysSink = LoggingProviderImpl.getLogManagerAccess() - .demandLoggerFor(LogManager.getLogManager(),"foo", Thread.class); + .demandLoggerFor(LogManager.getLogManager(),"foo", Thread.class.getModule()); appSink.addHandler(new MyHandler()); sysSink.addHandler(new MyHandler()); appSink.setUseParentHandlers(VERBOSE); diff --git a/jdk/test/sun/util/logging/PlatformLoggerTest.java b/jdk/test/sun/util/logging/PlatformLoggerTest.java index 0bf94d64a5a..530a2acea8a 100644 --- a/jdk/test/sun/util/logging/PlatformLoggerTest.java +++ b/jdk/test/sun/util/logging/PlatformLoggerTest.java @@ -197,7 +197,7 @@ public class PlatformLoggerTest { // create a brand new java logger Logger javaLogger = sun.util.logging.internal.LoggingProviderImpl.getLogManagerAccess() .demandLoggerFor(LogManager.getLogManager(), - logger.getName()+"."+level.getName(), Thread.class); + logger.getName()+"."+level.getName(), Thread.class.getModule()); // Set a non standard java.util.logging.Level on the java logger // (except for OFF & ALL - which will remain unchanged) From 607d8e443b0914fe25113e6af23e745b683aef7c Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Wed, 27 Apr 2016 18:52:32 +0200 Subject: [PATCH 160/222] 8155236: AIX: fix dectection of Xrender extension Reviewed-by: prr --- .../libawt_xawt/java2d/x11/XRBackendNative.c | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c b/jdk/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c index 733606ec444..f408b0178ea 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,8 +72,8 @@ typedef struct _XRadialGradient { #include -#if defined(__solaris__) || defined(_AIX) -/* Solaris 10 and AIX will not have these symbols at runtime */ +#if defined(__solaris__) +/* Solaris 10 will not have these symbols at compile time */ typedef Picture (*XRenderCreateLinearGradientFuncType) (Display *dpy, @@ -147,7 +147,22 @@ static jboolean IsXRenderAvailable(jboolean verbose, jboolean ignoreLinuxVersion return JNI_FALSE; } -#if defined(__solaris__) || defined(_AIX) +#if defined(_AIX) + // On AIX we have to use a special syntax because the shared libraries are packed in + // multi-architecture archives. We first try to load the system default libXrender + // which is contained in the 'X11.base.lib' fileset starting with AIX 6.1 + xrenderlib = dlopen("libXrender.a(shr_64.o)", RTLD_GLOBAL | RTLD_LAZY | RTLD_MEMBER); + if (xrenderlib == NULL) { + // If the latter wasn't successful, we also try to load the version under /opt/freeware + // This may be downloaded from the "AIX Toolbox for Linux Applications" even for AIX 5.3 + xrenderlib = dlopen("libXrender.a(libXrender.so.0)", RTLD_GLOBAL | RTLD_LAZY | RTLD_MEMBER); + } + if (xrenderlib != NULL) { + dlclose(xrenderlib); + } else { + available = JNI_FALSE; + } +#elif defined(__solaris__) xrenderlib = dlopen("libXrender.so",RTLD_GLOBAL|RTLD_LAZY); if (xrenderlib != NULL) { From 0b7775586ffeb3a549e06b297a2ec14a7a139d30 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Wed, 27 Apr 2016 20:18:49 +0200 Subject: [PATCH 161/222] 8155106: MHs.Lookup.findConstructor returns handles for array classes Reviewed-by: shade, sundar --- .../java/lang/invoke/MethodHandleImpl.java | 7 +- .../java/lang/invoke/MethodHandles.java | 24 +++++ .../lang/invoke/ArrayConstructorTest.java | 91 +++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/lang/invoke/ArrayConstructorTest.java diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index a108836ce51..782eff613ae 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -25,6 +25,7 @@ package java.lang.invoke; +import java.lang.reflect.Array; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; @@ -1892,7 +1893,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; MH_tryFinallyExec = 12, MH_tryFinallyVoidExec = 13, MH_decrementCounter = 14, - MH_LIMIT = 15; + MH_Array_newInstance = 15, + MH_LIMIT = 16; static MethodHandle getConstantHandle(int idx) { MethodHandle handle = HANDLES[idx]; @@ -1965,6 +1967,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; case MH_decrementCounter: return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "decrementCounter", MethodType.methodType(int.class, int.class)); + case MH_Array_newInstance: + return IMPL_LOOKUP.findStatic(Array.class, "newInstance", + MethodType.methodType(Object.class, Class.class, int.class)); } } catch (ReflectiveOperationException ex) { throw newInternalError(ex); diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index afe6aecc9f4..c3a97a178a3 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -1010,6 +1010,9 @@ assertEquals("[x, y, z]", pb.command().toString()); * @throws NullPointerException if any argument is null */ public MethodHandle findConstructor(Class refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { + if (refc.isArray()) { + throw new NoSuchMethodException("no constructor for array class: " + refc.getName()); + } String name = ""; MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type); return getDirectConstructor(refc, ctor); @@ -2220,6 +2223,27 @@ return mh1; static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_LOOKUP_CLASS, Lookup.PUBLIC); } + /** + * Produces a method handle constructing arrays of a desired type. + * The return type of the method handle will be the array type. + * The type of its sole argument will be {@code int}, which specifies the size of the array. + * @param arrayClass an array type + * @return a method handle which can create arrays of the given type + * @throws NullPointerException if the argument is {@code null} + * @throws IllegalArgumentException if {@code arrayClass} is not an array type + * @see java.lang.reflect.Array#newInstance(Class, int) + * @since 9 + */ + public static + MethodHandle arrayConstructor(Class arrayClass) throws IllegalArgumentException { + if (!arrayClass.isArray()) { + throw newIllegalArgumentException("not an array class: " + arrayClass.getName()); + } + MethodHandle ani = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_Array_newInstance). + bindTo(arrayClass.getComponentType()); + return ani.asType(ani.type().changeReturnType(arrayClass)); + } + /** * Produces a method handle giving read access to elements of an array. * The type of the method handle will have a return type of the array's diff --git a/jdk/test/java/lang/invoke/ArrayConstructorTest.java b/jdk/test/java/lang/invoke/ArrayConstructorTest.java new file mode 100644 index 00000000000..9d0ae66188e --- /dev/null +++ b/jdk/test/java/lang/invoke/ArrayConstructorTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* @test + * @bug 8155106 + * @run testng/othervm -ea -esa test.java.lang.invoke.ArrayConstructorTest + */ +package test.java.lang.invoke; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + +import static java.lang.invoke.MethodType.methodType; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + + +public class ArrayConstructorTest { + + static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + @Test + public static void testFindConstructorArray() { + boolean caught = false; + try { + MethodHandle h = LOOKUP.findConstructor(Object[].class, methodType(void.class)); + } catch (NoSuchMethodException nsme) { + assertEquals("no constructor for array class: [Ljava.lang.Object;", nsme.getMessage()); + caught = true; + } catch (Exception e) { + throw new AssertionError("unexpected exception: " + e); + } + assertTrue(caught); + } + + @DataProvider + static Object[][] arrayConstructorNegative() { + return new Object[][]{ + {String.class, IllegalArgumentException.class, "not an array class: java.lang.String"}, + {null, NullPointerException.class, null} + }; + } + + @Test(dataProvider = "arrayConstructorNegative") + public static void testArrayConstructorNegative(Class clazz, Class exceptionClass, String message) { + boolean caught = false; + try { + MethodHandle h = MethodHandles.arrayConstructor(clazz); + } catch (Exception e) { + assertEquals(exceptionClass, e.getClass()); + if (message != null) { + assertEquals(message, e.getMessage()); + } + caught = true; + } + assertTrue(caught); + } + + @Test + public static void testArrayConstructor() throws Throwable { + MethodHandle h = MethodHandles.arrayConstructor(String[].class); + assertEquals(methodType(String[].class, int.class), h.type()); + String[] a = (String[]) h.invoke(17); + assertEquals(17, a.length); + } + +} From f3402815334ce329c28f04836fcf96fe8b360f54 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 27 Apr 2016 12:06:51 -0700 Subject: [PATCH 162/222] 8154905: Rename jdk.jvmstat.rmi to jdk.jstatd Reviewed-by: alanb, sundar --- ...Launcher-jdk.jvmstat.rmi.gmk => Launcher-jdk.jstatd.gmk} | 0 .../share/classes/module-info.java | 2 +- .../classes/sun/jvmstat/monitor/remote/RemoteHost.java | 0 .../share/classes/sun/jvmstat/monitor/remote/RemoteVm.java | 0 .../share/classes/sun/jvmstat/monitor/remote/package.html | 0 .../monitor/protocol/rmi/MonitoredHostProvider.java | 0 .../monitor/protocol/rmi/MonitoredHostRmiService.java | 0 .../perfdata/monitor/protocol/rmi/PerfDataBuffer.java | 0 .../perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java | 0 .../perfdata/monitor/protocol/rmi/RemoteVmManager.java | 0 .../sun/jvmstat/perfdata/monitor/protocol/rmi/package.html | 0 .../share/classes/sun/tools/jstatd/Jstatd.java | 0 .../share/classes/sun/tools/jstatd/RemoteHostImpl.java | 0 .../share/classes/sun/tools/jstatd/RemoteVmImpl.java | 0 jdk/src/jdk.jvmstat/share/classes/module-info.java | 6 +++--- 15 files changed, 4 insertions(+), 4 deletions(-) rename jdk/make/launcher/{Launcher-jdk.jvmstat.rmi.gmk => Launcher-jdk.jstatd.gmk} (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/module-info.java (98%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/jvmstat/monitor/remote/package.html (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/tools/jstatd/Jstatd.java (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/tools/jstatd/RemoteHostImpl.java (100%) rename jdk/src/{jdk.jvmstat.rmi => jdk.jstatd}/share/classes/sun/tools/jstatd/RemoteVmImpl.java (100%) diff --git a/jdk/make/launcher/Launcher-jdk.jvmstat.rmi.gmk b/jdk/make/launcher/Launcher-jdk.jstatd.gmk similarity index 100% rename from jdk/make/launcher/Launcher-jdk.jvmstat.rmi.gmk rename to jdk/make/launcher/Launcher-jdk.jstatd.gmk diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/module-info.java b/jdk/src/jdk.jstatd/share/classes/module-info.java similarity index 98% rename from jdk/src/jdk.jvmstat.rmi/share/classes/module-info.java rename to jdk/src/jdk.jstatd/share/classes/module-info.java index 01ed37c3210..1f8a86e214d 100644 --- a/jdk/src/jdk.jvmstat.rmi/share/classes/module-info.java +++ b/jdk/src/jdk.jstatd/share/classes/module-info.java @@ -23,7 +23,7 @@ * questions. */ -module jdk.jvmstat.rmi { +module jdk.jstatd { requires java.rmi; requires jdk.jvmstat; diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java b/jdk/src/jdk.jstatd/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java rename to jdk/src/jdk.jstatd/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java b/jdk/src/jdk.jstatd/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java rename to jdk/src/jdk.jstatd/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/package.html b/jdk/src/jdk.jstatd/share/classes/sun/jvmstat/monitor/remote/package.html similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/package.html rename to jdk/src/jdk.jstatd/share/classes/sun/jvmstat/monitor/remote/package.html diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java b/jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java rename to jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java b/jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java rename to jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java b/jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java rename to jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java b/jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java rename to jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java b/jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java rename to jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html b/jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html rename to jdk/src/jdk.jstatd/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/Jstatd.java b/jdk/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/Jstatd.java rename to jdk/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/RemoteHostImpl.java b/jdk/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/RemoteHostImpl.java rename to jdk/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteHostImpl.java diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/RemoteVmImpl.java b/jdk/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteVmImpl.java similarity index 100% rename from jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/RemoteVmImpl.java rename to jdk/src/jdk.jstatd/share/classes/sun/tools/jstatd/RemoteVmImpl.java diff --git a/jdk/src/jdk.jvmstat/share/classes/module-info.java b/jdk/src/jdk.jvmstat/share/classes/module-info.java index 2510a362931..d0038c242b2 100644 --- a/jdk/src/jdk.jvmstat/share/classes/module-info.java +++ b/jdk/src/jdk.jvmstat/share/classes/module-info.java @@ -28,12 +28,12 @@ module jdk.jvmstat { jdk.attach, jdk.jcmd, jdk.jconsole, - jdk.jvmstat.rmi; + jdk.jstatd; exports sun.jvmstat.monitor.event to jdk.jcmd, - jdk.jvmstat.rmi; + jdk.jstatd; exports sun.jvmstat.perfdata.monitor to - jdk.jvmstat.rmi; + jdk.jstatd; uses sun.jvmstat.monitor.MonitoredHostService; provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService; From da78f43efc7f2a26f583045cb245c2c0e92ff827 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Wed, 27 Apr 2016 20:35:23 +0100 Subject: [PATCH 163/222] 8044773: Refactor jdk.net API so that it can be moved out of the base module Co-authored-by: Erik Joelsson Reviewed-by: alanb, erikj, mchung --- make/GensrcModuleInfo.gmk | 19 ++++++++++++++----- make/Javadoc.gmk | 2 +- make/common/Modules.gmk | 1 + 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/make/GensrcModuleInfo.gmk b/make/GensrcModuleInfo.gmk index 84bed9e8985..2fbcdc6ab24 100644 --- a/make/GensrcModuleInfo.gmk +++ b/make/GensrcModuleInfo.gmk @@ -78,21 +78,30 @@ ifneq ($(MOD_FILES), ) # let space represent new lines in the variable as $(shell) normalizes all # whitespace. $(foreach f, $(MOD_FILES), \ - $(eval MOD_FILE_CONTENTS += $(shell $(GREP) -v ".\*" $f | $(TR) ' ' '/'))) + $(eval MOD_FILE_CONTENTS += $(shell $(GREP) -v -e ".\*" -e "//" $f | $(TR) ' ' '/'))) + + # Separate the modifications into qualified exports and the rest + MODS_QUALIFIED_EXPORTS := $(call containing, /to/, $(MOD_FILE_CONTENTS)) + MODS_REST := $(filter-out $(MODS_QUALIFIED_EXPORTS), $(MOD_FILE_CONTENTS)) # Filter the contents for modules that are actually being built MODULES_FILTER := $(addprefix %/, $(addsuffix ;, $(ALL_MODULES))) - MODULES_FILTER += provides% - MODIFICATIONS := $(filter $(MODULES_FILTER), $(MOD_FILE_CONTENTS)) + MODIFICATIONS := $(filter $(MODULES_FILTER), $(MODS_QUALIFIED_EXPORTS)) \ + $(MODS_REST) # Convert the modification lines into arguments for the modification tool. # Filter out modifications for non existing to-modules. $(foreach line, $(MODIFICATIONS), \ $(eval split_line := $(subst /,$(SPACE),$(line))) \ $(eval command := $(word 1, $(split_line))) \ - $(eval package := $(word 2, $(split_line))) \ + $(eval package := $(patsubst %;,%,$(word 2, $(split_line)))) \ $(eval to_module := $(patsubst %;,%,$(word 4, $(split_line)))) \ - $(eval ARGS += -$(command) $(package)/$(to_module))) + $(if $(to_module), \ + $(eval ARGS += -$(command) $(package)/$(to_module)) \ + , \ + $(eval ARGS += -$(command) $(package)) \ + ) \ + ) ifneq ($(ARGS), ) $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java: \ diff --git a/make/Javadoc.gmk b/make/Javadoc.gmk index 2998dbf5242..d1e85b4b746 100644 --- a/make/Javadoc.gmk +++ b/make/Javadoc.gmk @@ -1580,7 +1580,7 @@ JDKNET_OPTIONS_FILE = $(DOCSTMPDIR)/jdknet.options JDKNET_PACKAGES_FILE = $(DOCSTMPDIR)/jdknet.packages # The modules required to be documented -JDKNET_MODULES = java.base +JDKNET_MODULES = jdk.net jdknetdocs: $(JDKNET_INDEX_HTML) diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index cba267b0075..dba855995d7 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -63,6 +63,7 @@ BOOT_MODULES += \ java.xml.crypto \ jdk.httpserver \ jdk.management \ + jdk.net \ jdk.sctp \ jdk.security.auth \ jdk.security.jgss \ From 07cef26155dee0957073ebaf2d57f745d0a32c5c Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Wed, 27 Apr 2016 20:36:02 +0100 Subject: [PATCH 164/222] 8044773: Refactor jdk.net API so that it can be moved out of the base module Reviewed-by: alanb, erikj, mchung --- jdk/make/lib/Lib-jdk.net.gmk | 51 +++ jdk/make/mapfiles/libextnet/mapfile-vers | 34 ++ jdk/make/mapfiles/libnet/mapfile-vers | 4 - .../tools/module/GenModuleInfoSource.java | 2 +- .../jdk/net/ExtendedSocketOptions.java | 61 ---- .../java.base/share/classes/module-info.java | 4 +- .../classes/sun/net/ExtendedOptionsImpl.java | 92 ----- .../sun/net/ext/ExtendedSocketOptions.java | 110 ++++++ .../nio/ch/AsynchronousSocketChannelImpl.java | 8 +- .../sun/nio/ch/DatagramChannelImpl.java | 8 +- .../share/classes/sun/nio/ch/Net.java | 25 +- .../classes/sun/nio/ch/SocketChannelImpl.java | 9 +- .../java/net/PlainDatagramSocketImpl.java | 44 +-- .../classes/java/net/PlainSocketImpl.java | 47 ++- .../unix/native/libnet/ExtendedOptionsImpl.c | 344 ------------------ .../unix/native/libnet/net_util_md.h | 41 --- .../jdk/net/ExtendedSocketOptions.java | 212 +++++++++++ .../classes/jdk/net/NetworkPermission.java | 0 .../share/classes/jdk/net/SocketFlow.java | 81 +++-- .../share/classes/jdk/net/Sockets.java | 33 +- .../share/classes/jdk/net/package-info.java | 0 .../jdk.net/share/classes/module-info.java | 29 ++ .../jdk/net/SolarisSocketOptions.java} | 67 ++-- .../native/libextnet/SolarisSocketOptions.c | 176 +++++++++ .../native/libextnet/SolarisSocketOptions.h | 79 ++++ .../share/classes/module-info.java | 1 + .../java/net/SocketOption/OptionsTest.java | 25 +- .../SocketOption/UnsupportedOptionsTest.java | 52 ++- .../DatagramChannel/SocketOptionTests.java | 4 +- .../SocketOptionTests.java | 4 +- .../SocketChannel/SocketOptionTests.java | 4 +- .../jdk/net/SocketFlow/SocketFlowBasic.java | 93 +++++ jdk/test/jdk/net/Sockets/Test.java | 165 +++++---- 33 files changed, 1096 insertions(+), 813 deletions(-) create mode 100644 jdk/make/lib/Lib-jdk.net.gmk create mode 100644 jdk/make/mapfiles/libextnet/mapfile-vers delete mode 100644 jdk/src/java.base/share/classes/jdk/net/ExtendedSocketOptions.java delete mode 100644 jdk/src/java.base/share/classes/sun/net/ExtendedOptionsImpl.java create mode 100644 jdk/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java delete mode 100644 jdk/src/java.base/unix/native/libnet/ExtendedOptionsImpl.c create mode 100644 jdk/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java rename jdk/src/{java.base => jdk.net}/share/classes/jdk/net/NetworkPermission.java (100%) rename jdk/src/{java.base => jdk.net}/share/classes/jdk/net/SocketFlow.java (69%) rename jdk/src/{java.base => jdk.net}/share/classes/jdk/net/Sockets.java (94%) rename jdk/src/{java.base => jdk.net}/share/classes/jdk/net/package-info.java (100%) create mode 100644 jdk/src/jdk.net/share/classes/module-info.java rename jdk/src/{java.base/windows/native/libnet/ExtendedOptionsImpl.c => jdk.net/solaris/classes/jdk/net/SolarisSocketOptions.java} (52%) create mode 100644 jdk/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c create mode 100644 jdk/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h create mode 100644 jdk/test/jdk/net/SocketFlow/SocketFlowBasic.java diff --git a/jdk/make/lib/Lib-jdk.net.gmk b/jdk/make/lib/Lib-jdk.net.gmk new file mode 100644 index 00000000000..69c789b2f08 --- /dev/null +++ b/jdk/make/lib/Lib-jdk.net.gmk @@ -0,0 +1,51 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# 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. +# + +include LibCommon.gmk + +################################################################################ + +ifeq ($(OPENJDK_TARGET_OS), solaris) + + $(eval $(call SetupNativeCompilation, BUILD_LIBEXTNET, \ + LIBRARY := extnet, \ + OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ + SRC := $(JDK_TOPDIR)/src/jdk.net/solaris/native/libextnet, \ + OPTIMIZATION := LOW, \ + CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/jdk.net, \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libextnet/mapfile-vers, \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ + $(call SET_SHARED_LIBRARY_ORIGIN), \ + LIBS := -lsocket -lc -ljava, \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libextnet, \ + )) + + $(BUILD_LIBEXTNET): $(call FindLib, java.base, java) + + TARGETS += $(BUILD_LIBEXTNET) +endif + + +################################################################################ diff --git a/jdk/make/mapfiles/libextnet/mapfile-vers b/jdk/make/mapfiles/libextnet/mapfile-vers new file mode 100644 index 00000000000..5dbc5b960aa --- /dev/null +++ b/jdk/make/mapfiles/libextnet/mapfile-vers @@ -0,0 +1,34 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# 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. +# + +SUNWprivate_1.1 { + global: + Java_jdk_net_SolarisSocketOptions_init; + Java_jdk_net_SolarisSocketOptions_setFlowOption; + Java_jdk_net_SolarisSocketOptions_getFlowOption; + Java_jdk_net_SolarisSocketOptions_flowSupported; + local: + *; +}; diff --git a/jdk/make/mapfiles/libnet/mapfile-vers b/jdk/make/mapfiles/libnet/mapfile-vers index 82247780181..92816bfa87d 100644 --- a/jdk/make/mapfiles/libnet/mapfile-vers +++ b/jdk/make/mapfiles/libnet/mapfile-vers @@ -98,10 +98,6 @@ SUNWprivate_1.1 { Java_sun_net_sdp_SdpSupport_create0; Java_sun_net_spi_DefaultProxySelector_init; Java_sun_net_spi_DefaultProxySelector_getSystemProxy; - Java_sun_net_ExtendedOptionsImpl_init; - Java_sun_net_ExtendedOptionsImpl_setFlowOption; - Java_sun_net_ExtendedOptionsImpl_getFlowOption; - Java_sun_net_ExtendedOptionsImpl_flowSupported; NET_AllocSockaddr; NET_SockaddrToInetAddress; NET_SockaddrEqualsInetAddress; diff --git a/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java b/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java index f2f404e9a0b..e7d932d1141 100644 --- a/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java +++ b/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java @@ -52,7 +52,7 @@ public class GenModuleInfoSource { "Usage: GenModuleInfoSource [option] -o \n" + "Options are:\n" + " -exports \n" + - " -exports /\n" + + " -exports [/]\n" + " -uses \n" + " -provides /\n"; diff --git a/jdk/src/java.base/share/classes/jdk/net/ExtendedSocketOptions.java b/jdk/src/java.base/share/classes/jdk/net/ExtendedSocketOptions.java deleted file mode 100644 index 12af5aff7ee..00000000000 --- a/jdk/src/java.base/share/classes/jdk/net/ExtendedSocketOptions.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 jdk.net; - -import java.net.SocketOption; - -/** - * Defines extended socket options, beyond those defined in - * {@link java.net.StandardSocketOptions}. These options may be platform - * specific. - * - * @since 1.8 - */ -public final class ExtendedSocketOptions { - - private static class ExtSocketOption implements SocketOption { - private final String name; - private final Class type; - ExtSocketOption(String name, Class type) { - this.name = name; - this.type = type; - } - @Override public String name() { return name; } - @Override public Class type() { return type; } - @Override public String toString() { return name; } - } - - private ExtendedSocketOptions() {} - - /** - * Service level properties. When a security manager is installed, - * setting or getting this option requires a {@link NetworkPermission} - * {@code ("setOption.SO_FLOW_SLA")} or {@code "getOption.SO_FLOW_SLA"} - * respectively. - */ - public static final SocketOption SO_FLOW_SLA = new - ExtSocketOption("SO_FLOW_SLA", SocketFlow.class); -} diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java index 942c0582ea0..12ad93f6a6d 100644 --- a/jdk/src/java.base/share/classes/module-info.java +++ b/jdk/src/java.base/share/classes/module-info.java @@ -83,8 +83,6 @@ module java.base { // see JDK-8144062 exports jdk; - // see JDK-8044773 - exports jdk.net; // the service types defined by the APIs in this module @@ -194,6 +192,8 @@ module java.base { jdk.jvmstat; exports sun.net to java.httpclient; + exports sun.net.ext to + jdk.net; exports sun.net.dns to java.security.jgss, jdk.naming.dns; diff --git a/jdk/src/java.base/share/classes/sun/net/ExtendedOptionsImpl.java b/jdk/src/java.base/share/classes/sun/net/ExtendedOptionsImpl.java deleted file mode 100644 index 8fbcdd7b49d..00000000000 --- a/jdk/src/java.base/share/classes/sun/net/ExtendedOptionsImpl.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 sun.net; - -import java.net.*; -import jdk.net.*; -import java.io.IOException; -import java.io.FileDescriptor; -import java.security.PrivilegedAction; -import java.security.AccessController; -import java.lang.reflect.Field; -import java.util.Set; -import java.util.HashSet; -import java.util.HashMap; -import java.util.Collections; - -/** - * Contains the native implementation for extended socket options - * together with some other static utilities - */ -public class ExtendedOptionsImpl { - - static { - AccessController.doPrivileged((PrivilegedAction)() -> { - System.loadLibrary("net"); - return null; - }); - init(); - } - - private ExtendedOptionsImpl() {} - - public static void checkSetOptionPermission(SocketOption option) { - SecurityManager sm = System.getSecurityManager(); - if (sm == null) { - return; - } - String check = "setOption." + option.name(); - sm.checkPermission(new NetworkPermission(check)); - } - - public static void checkGetOptionPermission(SocketOption option) { - SecurityManager sm = System.getSecurityManager(); - if (sm == null) { - return; - } - String check = "getOption." + option.name(); - sm.checkPermission(new NetworkPermission(check)); - } - - public static void checkValueType(Object value, Class type) { - if (!type.isAssignableFrom(value.getClass())) { - String s = "Found: " + value.getClass().toString() + " Expected: " - + type.toString(); - throw new IllegalArgumentException(s); - } - } - - private static native void init(); - - /* - * Extension native implementations - * - * SO_FLOW_SLA - */ - public static native void setFlowOption(FileDescriptor fd, SocketFlow f); - public static native void getFlowOption(FileDescriptor fd, SocketFlow f); - public static native boolean flowSupported(); -} diff --git a/jdk/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java b/jdk/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java new file mode 100644 index 00000000000..a3300c3c0e9 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.ext; + +import java.io.FileDescriptor; +import java.net.SocketException; +import java.net.SocketOption; +import java.util.Collections; +import java.util.Set; + +/** + * Defines the infrastructure to support extended socket options, beyond those + * defined in {@link java.net.StandardSocketOptions}. + * + * Extended socket options are accessed through the jdk.net API, which is in + * the jdk.net module. + */ +public abstract class ExtendedSocketOptions { + + private final Set> options; + + /** Tells whether or not the option is supported. */ + public final boolean isOptionSupported(SocketOption option) { + return options().contains(option); + } + + /** Return the, possibly empty, set of extended socket options available. */ + public final Set> options() { return options; } + + /** Sets the value of a socket option, for the given socket. */ + public abstract void setOption(FileDescriptor fd, SocketOption option, Object value) + throws SocketException; + + /** Returns the value of a socket option, for the given socket. */ + public abstract Object getOption(FileDescriptor fd, SocketOption option) + throws SocketException; + + protected ExtendedSocketOptions(Set> options) { + this.options = options; + } + + private static volatile ExtendedSocketOptions instance; + + public static final ExtendedSocketOptions getInstance() { return instance; } + + /** Registers support for extended socket options. Invoked by the jdk.net module. */ + public static final void register(ExtendedSocketOptions extOptions) { + if (instance != null) + throw new InternalError("Attempting to reregister extended options"); + + instance = extOptions; + } + + static { + try { + // If the class is present, it will be initialized which + // triggers registration of the extended socket options. + Class c = Class.forName("jdk.net.ExtendedSocketOptions"); + } catch (ClassNotFoundException e) { + // the jdk.net module is not present => no extended socket options + instance = new NoExtendedSocketOptions(); + } + } + + static final class NoExtendedSocketOptions extends ExtendedSocketOptions { + + NoExtendedSocketOptions() { + super(Collections.>emptySet()); + } + + @Override + public void setOption(FileDescriptor fd, SocketOption option, Object value) + throws SocketException + { + throw new UnsupportedOperationException( + "no extended options: " + option.name()); + } + + @Override + public Object getOption(FileDescriptor fd, SocketOption option) + throws SocketException + { + throw new UnsupportedOperationException( + "no extended options: " + option.name()); + } + } +} diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java index 36b3c1b7ab9..1faf49b8578 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java @@ -39,7 +39,7 @@ import java.util.Collections; import java.util.concurrent.*; import java.util.concurrent.locks.*; import sun.net.NetHooks; -import sun.net.ExtendedOptionsImpl; +import sun.net.ext.ExtendedSocketOptions; /** * Base implementation of AsynchronousSocketChannel @@ -512,9 +512,9 @@ abstract class AsynchronousSocketChannelImpl set.add(StandardSocketOptions.SO_REUSEPORT); } set.add(StandardSocketOptions.TCP_NODELAY); - if (ExtendedOptionsImpl.flowSupported()) { - set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); - } + ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + set.addAll(extendedOptions.options()); return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 77d14619222..f063e13ac13 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -33,7 +33,7 @@ import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; import sun.net.ResourceManager; -import sun.net.ExtendedOptionsImpl; +import sun.net.ext.ExtendedSocketOptions; /** * An implementation of DatagramChannels. @@ -306,9 +306,9 @@ class DatagramChannelImpl set.add(StandardSocketOptions.IP_MULTICAST_IF); set.add(StandardSocketOptions.IP_MULTICAST_TTL); set.add(StandardSocketOptions.IP_MULTICAST_LOOP); - if (ExtendedOptionsImpl.flowSupported()) { - set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); - } + ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + set.addAll(extendedOptions.options()); return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java index 9a5c4dcb6f8..59d3167745b 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java @@ -27,15 +27,13 @@ package sun.nio.ch; import java.io.*; import java.net.*; -import jdk.net.*; import java.nio.channels.*; import java.util.*; import java.security.AccessController; import java.security.PrivilegedAction; -import sun.net.ExtendedOptionsImpl; +import sun.net.ext.ExtendedSocketOptions; import sun.security.action.GetPropertyAction; - public class Net { private Net() { } @@ -281,6 +279,9 @@ public class Net { // -- Socket options + static final ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + static void setSocketOption(FileDescriptor fd, ProtocolFamily family, SocketOption name, Object value) throws IOException @@ -291,12 +292,8 @@ public class Net { // only simple values supported by this method Class type = name.type(); - if (type == SocketFlow.class) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new NetworkPermission("setOption.SO_FLOW_SLA")); - } - ExtendedOptionsImpl.setFlowOption(fd, (SocketFlow)value); + if (extendedOptions.isOptionSupported(name)) { + extendedOptions.setOption(fd, name, value); return; } @@ -353,14 +350,8 @@ public class Net { { Class type = name.type(); - if (type == SocketFlow.class) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new NetworkPermission("getOption.SO_FLOW_SLA")); - } - SocketFlow flow = SocketFlow.create(); - ExtendedOptionsImpl.getFlowOption(fd, flow); - return flow; + if (extendedOptions.isOptionSupported(name)) { + return extendedOptions.getOption(fd, name); } // only simple values supported by this method diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java index c4644920c3e..856e0cf2fb6 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -33,8 +33,7 @@ import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; import sun.net.NetHooks; -import sun.net.ExtendedOptionsImpl; - +import sun.net.ext.ExtendedSocketOptions; /** * An implementation of SocketChannels @@ -242,9 +241,9 @@ class SocketChannelImpl // additional options required by socket adaptor set.add(StandardSocketOptions.IP_TOS); set.add(ExtendedSocketOption.SO_OOBINLINE); - if (ExtendedOptionsImpl.flowSupported()) { - set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); - } + ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + set.addAll(extendedOptions.options()); return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java index f7c65931613..32640dff272 100644 --- a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java +++ b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java @@ -27,9 +27,7 @@ package java.net; import java.io.IOException; import java.util.Set; import java.util.HashSet; -import java.util.Collections; -import jdk.net.*; -import static sun.net.ExtendedOptionsImpl.*; +import sun.net.ext.ExtendedSocketOptions; /* * On Unix systems we simply delegate to native methods. @@ -43,8 +41,11 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl init(); } + static final ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + protected void setOption(SocketOption name, T value) throws IOException { - if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + if (!extendedOptions.isOptionSupported(name)) { if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { super.setOption(name, value); } else { @@ -55,21 +56,16 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl } } } else { - if (!flowSupported()) { - throw new UnsupportedOperationException("unsupported option"); - } if (isClosed()) { throw new SocketException("Socket closed"); } - checkSetOptionPermission(name); - checkValueType(value, SocketFlow.class); - setFlowOption(getFileDescriptor(), (SocketFlow)value); + extendedOptions.setOption(fd, name, value); } } @SuppressWarnings("unchecked") protected T getOption(SocketOption name) throws IOException { - if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + if (!extendedOptions.isOptionSupported(name)) { if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { return super.getOption(name); } else { @@ -79,31 +75,23 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl throw new UnsupportedOperationException("unsupported option"); } } + } else { + if (isClosed()) { + throw new SocketException("Socket closed"); + } + return (T) extendedOptions.getOption(fd, name); } - if (!flowSupported()) { - throw new UnsupportedOperationException("unsupported option"); - } - if (isClosed()) { - throw new SocketException("Socket closed"); - } - checkGetOptionPermission(name); - SocketFlow flow = SocketFlow.create(); - getFlowOption(getFileDescriptor(), flow); - return (T)flow; } protected Set> supportedOptions() { - HashSet> options = new HashSet<>( - super.supportedOptions()); - - if (flowSupported()) { - options.add(ExtendedSocketOptions.SO_FLOW_SLA); - } + HashSet> options = new HashSet<>(super.supportedOptions()); + options.addAll(extendedOptions.options()); return options; } protected void socketSetOption(int opt, Object val) throws SocketException { - if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + if (opt == SocketOptions.SO_REUSEPORT && + !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { throw new UnsupportedOperationException("unsupported option"); } try { diff --git a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java index 2ec573ea5a9..4a5f2b5ddd6 100644 --- a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java +++ b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java @@ -28,10 +28,7 @@ import java.io.IOException; import java.io.FileDescriptor; import java.util.Set; import java.util.HashSet; -import java.util.Collections; -import jdk.net.*; - -import static sun.net.ExtendedOptionsImpl.*; +import sun.net.ext.ExtendedSocketOptions; /* * On Unix systems we simply delegate to native methods. @@ -57,8 +54,11 @@ class PlainSocketImpl extends AbstractPlainSocketImpl this.fd = fd; } + static final ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + protected void setOption(SocketOption name, T value) throws IOException { - if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + if (!extendedOptions.isOptionSupported(name)) { if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { super.setOption(name, value); } else { @@ -69,21 +69,19 @@ class PlainSocketImpl extends AbstractPlainSocketImpl } } } else { - if (getSocket() == null || !flowSupported()) { + if (getSocket() == null) { throw new UnsupportedOperationException("unsupported option"); } if (isClosedOrPending()) { throw new SocketException("Socket closed"); } - checkSetOptionPermission(name); - checkValueType(value, SocketFlow.class); - setFlowOption(getFileDescriptor(), (SocketFlow)value); + extendedOptions.setOption(fd, name, value); } } @SuppressWarnings("unchecked") protected T getOption(SocketOption name) throws IOException { - if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + if (!extendedOptions.isOptionSupported(name)) { if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { return super.getOption(name); } else { @@ -93,31 +91,28 @@ class PlainSocketImpl extends AbstractPlainSocketImpl throw new UnsupportedOperationException("unsupported option"); } } + } else { + if (getSocket() == null) { + throw new UnsupportedOperationException("unsupported option"); + } + if (isClosedOrPending()) { + throw new SocketException("Socket closed"); + } + return (T) extendedOptions.getOption(fd, name); } - if (getSocket() == null || !flowSupported()) { - throw new UnsupportedOperationException("unsupported option"); - } - if (isClosedOrPending()) { - throw new SocketException("Socket closed"); - } - checkGetOptionPermission(name); - SocketFlow flow = SocketFlow.create(); - getFlowOption(getFileDescriptor(), flow); - return (T)flow; } protected Set> supportedOptions() { - HashSet> options = new HashSet<>( - super.supportedOptions()); - - if (getSocket() != null && flowSupported()) { - options.add(ExtendedSocketOptions.SO_FLOW_SLA); + HashSet> options = new HashSet<>(super.supportedOptions()); + if (getSocket() != null) { + options.addAll(extendedOptions.options()); } return options; } protected void socketSetOption(int opt, boolean b, Object val) throws SocketException { - if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + if (opt == SocketOptions.SO_REUSEPORT && + !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { throw new UnsupportedOperationException("unsupported option"); } try { diff --git a/jdk/src/java.base/unix/native/libnet/ExtendedOptionsImpl.c b/jdk/src/java.base/unix/native/libnet/ExtendedOptionsImpl.c deleted file mode 100644 index 116d2e97d92..00000000000 --- a/jdk/src/java.base/unix/native/libnet/ExtendedOptionsImpl.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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. - */ - -#include -#include - -#include "net_util.h" -#include "jdk_net_SocketFlow.h" - -static jclass sf_status_class; /* Status enum type */ - -static jfieldID sf_status; -static jfieldID sf_priority; -static jfieldID sf_bandwidth; - -static jfieldID sf_fd_fdID; /* FileDescriptor.fd */ - -/* References to the literal enum values */ - -static jobject sfs_NOSTATUS; -static jobject sfs_OK; -static jobject sfs_NOPERMISSION; -static jobject sfs_NOTCONNECTED; -static jobject sfs_NOTSUPPORTED; -static jobject sfs_ALREADYCREATED; -static jobject sfs_INPROGRESS; -static jobject sfs_OTHER; - -static jobject getEnumField(JNIEnv *env, char *name); -static void setStatus(JNIEnv *env, jobject obj, int errval); - -/* OS specific code is implemented in these three functions */ - -static jboolean flowSupported0() ; - -/* - * Class: sun_net_ExtendedOptionsImpl - * Method: init - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init - (JNIEnv *env, jclass UNUSED) -{ - static int initialized = 0; - jclass c; - - /* Global class references */ - - if (initialized) { - return; - } - - c = (*env)->FindClass(env, "jdk/net/SocketFlow$Status"); - CHECK_NULL(c); - sf_status_class = (*env)->NewGlobalRef(env, c); - CHECK_NULL(sf_status_class); - - /* int "fd" field of java.io.FileDescriptor */ - - c = (*env)->FindClass(env, "java/io/FileDescriptor"); - CHECK_NULL(c); - sf_fd_fdID = (*env)->GetFieldID(env, c, "fd", "I"); - CHECK_NULL(sf_fd_fdID); - - - /* SocketFlow fields */ - - c = (*env)->FindClass(env, "jdk/net/SocketFlow"); - CHECK_NULL(c); - - /* status */ - - sf_status = (*env)->GetFieldID(env, c, "status", - "Ljdk/net/SocketFlow$Status;"); - CHECK_NULL(sf_status); - - /* priority */ - - sf_priority = (*env)->GetFieldID(env, c, "priority", "I"); - CHECK_NULL(sf_priority); - - /* bandwidth */ - - sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J"); - CHECK_NULL(sf_bandwidth); - - /* Initialize the static enum values */ - - sfs_NOSTATUS = getEnumField(env, "NO_STATUS"); - CHECK_NULL(sfs_NOSTATUS); - sfs_OK = getEnumField(env, "OK"); - CHECK_NULL(sfs_OK); - sfs_NOPERMISSION = getEnumField(env, "NO_PERMISSION"); - CHECK_NULL(sfs_NOPERMISSION); - sfs_NOTCONNECTED = getEnumField(env, "NOT_CONNECTED"); - CHECK_NULL(sfs_NOTCONNECTED); - sfs_NOTSUPPORTED = getEnumField(env, "NOT_SUPPORTED"); - CHECK_NULL(sfs_NOTSUPPORTED); - sfs_ALREADYCREATED = getEnumField(env, "ALREADY_CREATED"); - CHECK_NULL(sfs_ALREADYCREATED); - sfs_INPROGRESS = getEnumField(env, "IN_PROGRESS"); - CHECK_NULL(sfs_INPROGRESS); - sfs_OTHER = getEnumField(env, "OTHER"); - CHECK_NULL(sfs_OTHER); - initialized = JNI_TRUE; -} - -static jobject getEnumField(JNIEnv *env, char *name) -{ - jobject f; - jfieldID fID = (*env)->GetStaticFieldID(env, sf_status_class, name, - "Ljdk/net/SocketFlow$Status;"); - CHECK_NULL_RETURN(fID, NULL); - - f = (*env)->GetStaticObjectField(env, sf_status_class, fID); - CHECK_NULL_RETURN(f, NULL); - f = (*env)->NewGlobalRef(env, f); - CHECK_NULL_RETURN(f, NULL); - return f; -} - -/* - * Retrieve the int file-descriptor from a public socket type object. - * Gets impl, then the FileDescriptor from the impl, and then the fd - * from that. - */ -static int getFD(JNIEnv *env, jobject fileDesc) { - return (*env)->GetIntField(env, fileDesc, sf_fd_fdID); -} - -/** - * Sets the status field of a SocketFlow to one of the - * canned enum values - */ -static void setStatus (JNIEnv *env, jobject obj, int errval) -{ - switch (errval) { - case 0: /* OK */ - (*env)->SetObjectField(env, obj, sf_status, sfs_OK); - break; - case EPERM: - (*env)->SetObjectField(env, obj, sf_status, sfs_NOPERMISSION); - break; - case ENOTCONN: - (*env)->SetObjectField(env, obj, sf_status, sfs_NOTCONNECTED); - break; - case EOPNOTSUPP: - (*env)->SetObjectField(env, obj, sf_status, sfs_NOTSUPPORTED); - break; - case EALREADY: - (*env)->SetObjectField(env, obj, sf_status, sfs_ALREADYCREATED); - break; - case EINPROGRESS: - (*env)->SetObjectField(env, obj, sf_status, sfs_INPROGRESS); - break; - default: - (*env)->SetObjectField(env, obj, sf_status, sfs_OTHER); - break; - } -} - -#ifdef __solaris__ - -/* - * Class: sun_net_ExtendedOptionsImpl - * Method: setFlowOption - * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V - */ -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - int fd = getFD(env, fileDesc); - - if (fd < 0) { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); - return; - } else { - sock_flow_props_t props; - jlong bandwidth; - int rv; - - jint priority = (*env)->GetIntField(env, flow, sf_priority); - memset(&props, 0, sizeof(props)); - props.sfp_version = SOCK_FLOW_PROP_VERSION1; - - if (priority != jdk_net_SocketFlow_UNSET) { - props.sfp_mask |= SFP_PRIORITY; - props.sfp_priority = priority; - } - bandwidth = (*env)->GetLongField(env, flow, sf_bandwidth); - if (bandwidth > -1) { - props.sfp_mask |= SFP_MAXBW; - props.sfp_maxbw = (uint64_t) bandwidth; - } - rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); - if (rv < 0) { - if (errno == ENOPROTOOPT) { - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); - } else if (errno == EACCES || errno == EPERM) { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", - "Permission denied"); - } else { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", - "set option SO_FLOW_SLA failed"); - } - return; - } - setStatus(env, flow, props.sfp_status); - } -} - -/* - * Class: sun_net_ExtendedOptionsImpl - * Method: getFlowOption - * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V - */ -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - int fd = getFD(env, fileDesc); - - if (fd < 0) { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); - return; - } else { - sock_flow_props_t props; - int status; - socklen_t sz = sizeof(props); - - int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz); - if (rv < 0) { - if (errno == ENOPROTOOPT) { - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); - } else if (errno == EACCES || errno == EPERM) { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", - "Permission denied"); - } else { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", - "set option SO_FLOW_SLA failed"); - } - return; - } - /* first check status to see if flow exists */ - status = props.sfp_status; - setStatus(env, flow, status); - if (status == 0) { /* OK */ - /* can set the other fields now */ - if (props.sfp_mask & SFP_PRIORITY) { - (*env)->SetIntField(env, flow, sf_priority, props.sfp_priority); - } - if (props.sfp_mask & SFP_MAXBW) { - (*env)->SetLongField(env, flow, sf_bandwidth, - (jlong)props.sfp_maxbw); - } - } - } -} - -static jboolean flowsupported; -static jboolean flowsupported_set = JNI_FALSE; - -static jboolean flowSupported0() -{ - /* Do a simple dummy call, and try to figure out from that */ - sock_flow_props_t props; - int rv, s; - if (flowsupported_set) { - return flowsupported; - } - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s < 0) { - flowsupported = JNI_FALSE; - flowsupported_set = JNI_TRUE; - return JNI_FALSE; - } - memset(&props, 0, sizeof(props)); - props.sfp_version = SOCK_FLOW_PROP_VERSION1; - props.sfp_mask |= SFP_PRIORITY; - props.sfp_priority = SFP_PRIO_NORMAL; - rv = setsockopt(s, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); - if (rv != 0 && errno == ENOPROTOOPT) { - rv = JNI_FALSE; - } else { - rv = JNI_TRUE; - } - close(s); - flowsupported = rv; - flowsupported_set = JNI_TRUE; - return flowsupported; -} - -#else /* __solaris__ */ - -/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */ - -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); -} - -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); -} - -static jboolean flowSupported0() { - return JNI_FALSE; -} - -#endif /* __solaris__ */ - -JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported - (JNIEnv *env, jclass UNUSED) -{ - return flowSupported0(); -} diff --git a/jdk/src/java.base/unix/native/libnet/net_util_md.h b/jdk/src/java.base/unix/native/libnet/net_util_md.h index f440bd8ae6a..3a8c9f4d48e 100644 --- a/jdk/src/java.base/unix/native/libnet/net_util_md.h +++ b/jdk/src/java.base/unix/native/libnet/net_util_md.h @@ -120,47 +120,6 @@ int getDefaultIPv6Interface(struct in6_addr *target_addr); #ifdef __solaris__ int net_getParam(char *driver, char *param); - -#ifndef SO_FLOW_SLA -#define SO_FLOW_SLA 0x1018 - -#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 -#pragma pack(4) #endif -/* - * Used with the setsockopt(SO_FLOW_SLA, ...) call to set - * per socket service level properties. - * When the application uses per-socket API, we will enforce the properties - * on both outbound and inbound packets. - * - * For now, only priority and maxbw are supported in SOCK_FLOW_PROP_VERSION1. - */ -typedef struct sock_flow_props_s { - int sfp_version; - uint32_t sfp_mask; - int sfp_priority; /* flow priority */ - uint64_t sfp_maxbw; /* bandwidth limit in bps */ - int sfp_status; /* flow create status for getsockopt */ -} sock_flow_props_t; - -#define SOCK_FLOW_PROP_VERSION1 1 - -/* bit mask values for sfp_mask */ -#define SFP_MAXBW 0x00000001 /* Flow Bandwidth Limit */ -#define SFP_PRIORITY 0x00000008 /* Flow priority */ - -/* possible values for sfp_priority */ -#define SFP_PRIO_NORMAL 1 -#define SFP_PRIO_HIGH 2 - -#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 -#pragma pack() -#endif /* _LONG_LONG_ALIGNMENT */ - -#endif /* SO_FLOW_SLA */ -#endif /* __solaris__ */ - -JNIEXPORT jboolean JNICALL NET_IsFlowSupported(); - #endif /* NET_UTILS_MD_H */ diff --git a/jdk/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java b/jdk/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java new file mode 100644 index 00000000000..bcae6ce2251 --- /dev/null +++ b/jdk/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 jdk.net; + +import java.io.FileDescriptor; +import java.net.SocketException; +import java.net.SocketOption; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.Set; +import jdk.internal.misc.JavaIOFileDescriptorAccess; +import jdk.internal.misc.SharedSecrets; + +/** + * Defines extended socket options, beyond those defined in + * {@link java.net.StandardSocketOptions}. These options may be platform + * specific. + * + * @since 1.8 + */ +public final class ExtendedSocketOptions { + + private static class ExtSocketOption implements SocketOption { + private final String name; + private final Class type; + ExtSocketOption(String name, Class type) { + this.name = name; + this.type = type; + } + @Override public String name() { return name; } + @Override public Class type() { return type; } + @Override public String toString() { return name; } + } + + private ExtendedSocketOptions() { } + + /** + * Service level properties. When a security manager is installed, + * setting or getting this option requires a {@link NetworkPermission} + * {@code ("setOption.SO_FLOW_SLA")} or {@code "getOption.SO_FLOW_SLA"} + * respectively. + */ + public static final SocketOption SO_FLOW_SLA = new + ExtSocketOption("SO_FLOW_SLA", SocketFlow.class); + + + private static final PlatformSocketOptions platformSocketOptions = + PlatformSocketOptions.get(); + + private static final boolean flowSupported = + platformSocketOptions.flowSupported(); + + private static final Set> extendedOptions = options(); + + static Set> options() { + if (flowSupported) + return Set.of(SO_FLOW_SLA); + else + return Collections.>emptySet(); + } + + static { + // Registers the extended socket options with the base module. + sun.net.ext.ExtendedSocketOptions.register( + new sun.net.ext.ExtendedSocketOptions(extendedOptions) { + + @Override + public void setOption(FileDescriptor fd, + SocketOption option, + Object value) + throws SocketException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new NetworkPermission("setOption." + option.name())); + + if (fd == null || !fd.valid()) + throw new SocketException("socket closed"); + + if (option == SO_FLOW_SLA) { + assert flowSupported; + SocketFlow flow = checkValueType(value, option.type()); + setFlowOption(fd, flow); + } else { + throw new InternalError("Unexpected option " + option); + } + } + + @Override + public Object getOption(FileDescriptor fd, + SocketOption option) + throws SocketException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new NetworkPermission("getOption." + option.name())); + + if (fd == null || !fd.valid()) + throw new SocketException("socket closed"); + + if (option == SO_FLOW_SLA) { + assert flowSupported; + SocketFlow flow = SocketFlow.create(); + getFlowOption(fd, flow); + return flow; + } else { + throw new InternalError("Unexpected option " + option); + } + } + }); + } + + @SuppressWarnings("unchecked") + private static T checkValueType(Object value, Class type) { + if (!type.isAssignableFrom(value.getClass())) { + String s = "Found: " + value.getClass() + ", Expected: " + type; + throw new IllegalArgumentException(s); + } + return (T) value; + } + + private static final JavaIOFileDescriptorAccess fdAccess = + SharedSecrets.getJavaIOFileDescriptorAccess(); + + private static void setFlowOption(FileDescriptor fd, SocketFlow f) + throws SocketException + { + int status = platformSocketOptions.setFlowOption(fdAccess.get(fd), + f.priority(), + f.bandwidth()); + f.status(status); // augment the given flow with the status + } + + private static void getFlowOption(FileDescriptor fd, SocketFlow f) + throws SocketException + { + int status = platformSocketOptions.getFlowOption(fdAccess.get(fd), f); + f.status(status); // augment the given flow with the status + } + + static class PlatformSocketOptions { + + protected PlatformSocketOptions() {} + + @SuppressWarnings("unchecked") + private static PlatformSocketOptions newInstance(String cn) { + Class c; + try { + c = (Class)Class.forName(cn); + return c.getConstructor(new Class[] { }).newInstance(); + } catch (ReflectiveOperationException x) { + throw new AssertionError(x); + } + } + + private static PlatformSocketOptions create() { + String osname = AccessController.doPrivileged( + new PrivilegedAction() { + public String run() { + return System.getProperty("os.name"); + } + }); + if ("SunOS".equals(osname)) + return newInstance("jdk.net.SolarisSocketOptions"); + return new PlatformSocketOptions(); + } + + private static final PlatformSocketOptions instance = create(); + + static PlatformSocketOptions get() { + return instance; + } + + int setFlowOption(int fd, int priority, long bandwidth) + throws SocketException + { + throw new UnsupportedOperationException("unsupported socket option"); + } + + int getFlowOption(int fd, SocketFlow f) throws SocketException { + throw new UnsupportedOperationException("unsupported socket option"); + } + + boolean flowSupported() { + return false; + } + } +} diff --git a/jdk/src/java.base/share/classes/jdk/net/NetworkPermission.java b/jdk/src/jdk.net/share/classes/jdk/net/NetworkPermission.java similarity index 100% rename from jdk/src/java.base/share/classes/jdk/net/NetworkPermission.java rename to jdk/src/jdk.net/share/classes/jdk/net/NetworkPermission.java diff --git a/jdk/src/java.base/share/classes/jdk/net/SocketFlow.java b/jdk/src/jdk.net/share/classes/jdk/net/SocketFlow.java similarity index 69% rename from jdk/src/java.base/share/classes/jdk/net/SocketFlow.java rename to jdk/src/jdk.net/share/classes/jdk/net/SocketFlow.java index 12d1ed386d1..91c62cfa3d4 100644 --- a/jdk/src/java.base/share/classes/jdk/net/SocketFlow.java +++ b/jdk/src/jdk.net/share/classes/jdk/net/SocketFlow.java @@ -47,17 +47,18 @@ import java.lang.annotation.Native; */ public class SocketFlow { - private static final int UNSET = -1; + @Native public static final int UNSET = -1; @Native public static final int NORMAL_PRIORITY = 1; @Native public static final int HIGH_PRIORITY = 2; - private int priority = NORMAL_PRIORITY; - - private long bandwidth = UNSET; - - private Status status = Status.NO_STATUS; - - private SocketFlow() {} + @Native private static final int NO_STATUS_VALUE = 0; + @Native private static final int OK_VALUE = 1; + @Native private static final int NO_PERMISSION_VALUE = 2; + @Native private static final int NOT_CONNECTED_VALUE = 3; + @Native private static final int NOT_SUPPORTED_VALUE = 4; + @Native private static final int ALREADY_CREATED_VALUE = 5; + @Native private static final int IN_PROGRESS_VALUE = 6; + @Native private static final int OTHER_VALUE = 7; /** * Enumeration of the return values from the SO_FLOW_SLA @@ -72,37 +73,56 @@ public class SocketFlow { * Set or get socket option has not been called yet. Status * values can only be retrieved after calling set or get. */ - NO_STATUS, + NO_STATUS(NO_STATUS_VALUE), /** * Flow successfully created. */ - OK, + OK(OK_VALUE), /** * Caller has no permission to create flow. */ - NO_PERMISSION, + NO_PERMISSION(NO_PERMISSION_VALUE), /** * Flow can not be created because socket is not connected. */ - NOT_CONNECTED, + NOT_CONNECTED(NOT_CONNECTED_VALUE), /** * Flow creation not supported for this socket. */ - NOT_SUPPORTED, + NOT_SUPPORTED(NOT_SUPPORTED_VALUE), /** * A flow already exists with identical attributes. */ - ALREADY_CREATED, + ALREADY_CREATED(ALREADY_CREATED_VALUE), /** * A flow is being created. */ - IN_PROGRESS, + IN_PROGRESS(IN_PROGRESS_VALUE), /** * Some other unspecified error. */ - OTHER + OTHER(OTHER_VALUE); + + private final int value; + Status(int value) { this.value = value; } + + static Status from(int value) { + if (value == NO_STATUS.value) return NO_STATUS; + else if (value == OK.value) return OK; + else if (value == NO_PERMISSION.value) return NO_PERMISSION; + else if (value == NOT_CONNECTED.value) return NOT_CONNECTED; + else if (value == NOT_SUPPORTED.value) return NOT_SUPPORTED; + else if (value == ALREADY_CREATED.value) return ALREADY_CREATED; + else if (value == IN_PROGRESS.value) return IN_PROGRESS; + else if (value == OTHER.value) return OTHER; + else throw new InternalError("Unknown value: " + value); + } } + private int priority = NORMAL_PRIORITY; + private long bandwidth = UNSET; + private Status status = Status.NO_STATUS; + /** * Creates a new SocketFlow that can be used to set the SO_FLOW_SLA * socket option and create a socket flow. @@ -111,6 +131,8 @@ public class SocketFlow { return new SocketFlow(); } + private SocketFlow() { } + /** * Sets this SocketFlow's priority. Must be either NORMAL_PRIORITY * HIGH_PRIORITY. If not set, a flow's priority is normal. @@ -119,9 +141,8 @@ public class SocketFlow { * HIGH_PRIORITY. */ public SocketFlow priority(int priority) { - if (priority != NORMAL_PRIORITY && priority != HIGH_PRIORITY) { - throw new IllegalArgumentException("invalid priority"); - } + if (priority != NORMAL_PRIORITY && priority != HIGH_PRIORITY) + throw new IllegalArgumentException("invalid priority :" + priority); this.priority = priority; return this; } @@ -133,11 +154,9 @@ public class SocketFlow { * @throws IllegalArgumentException if bandwidth is less than zero. */ public SocketFlow bandwidth(long bandwidth) { - if (bandwidth < 0) { - throw new IllegalArgumentException("invalid bandwidth"); - } else { - this.bandwidth = bandwidth; - } + if (bandwidth < 0) + throw new IllegalArgumentException("invalid bandwidth: " + bandwidth); + this.bandwidth = bandwidth; return this; } @@ -164,4 +183,18 @@ public class SocketFlow { public Status status() { return status; } + + void status(int status) { + this.status = Status.from(status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(super.toString()); + sb.append(" [ priority=").append(priority()) + .append(", bandwidth=").append(bandwidth()) + .append(", status=").append(status()) + .append(" ]"); + return sb.toString(); + } } diff --git a/jdk/src/java.base/share/classes/jdk/net/Sockets.java b/jdk/src/jdk.net/share/classes/jdk/net/Sockets.java similarity index 94% rename from jdk/src/java.base/share/classes/jdk/net/Sockets.java rename to jdk/src/jdk.net/share/classes/jdk/net/Sockets.java index a8b78b044d8..983fe38956f 100644 --- a/jdk/src/java.base/share/classes/jdk/net/Sockets.java +++ b/jdk/src/jdk.net/share/classes/jdk/net/Sockets.java @@ -27,15 +27,12 @@ package jdk.net; import java.net.*; import java.io.IOException; -import java.io.FileDescriptor; -import java.security.PrivilegedAction; -import java.security.AccessController; -import java.lang.reflect.Field; -import java.util.Set; -import java.util.HashSet; -import java.util.HashMap; import java.util.Collections; -import sun.net.ExtendedOptionsImpl; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; /** * Defines static methods to set and get socket options defined by the @@ -57,12 +54,8 @@ import sun.net.ExtendedOptionsImpl; */ public class Sockets { - private static final HashMap,Set>> - options = new HashMap<>(); - - static { - initOptionSets(); - } + private static final Map,Set>> + options = optionSets(); private Sockets() {} @@ -259,14 +252,16 @@ public class Sockets { */ static boolean isReusePortAvailable() { if (!checkedReusePort) { - isReusePortAvailable = isReusePortAvailable0(); + Set> s = new Socket().supportedOptions(); + isReusePortAvailable = s.contains(StandardSocketOptions.SO_REUSEPORT); checkedReusePort = true; } return isReusePortAvailable; } - private static void initOptionSets() { - boolean flowsupported = ExtendedOptionsImpl.flowSupported(); + private static Map,Set>> optionSets() { + Map,Set>> options = new HashMap<>(); + boolean flowsupported = PlatformSocketOptions.get().flowSupported(); boolean reuseportsupported = isReusePortAvailable(); // Socket @@ -333,7 +328,7 @@ public class Sockets { } set = Collections.unmodifiableSet(set); options.put(MulticastSocket.class, set); - } - private static native boolean isReusePortAvailable0(); + return Collections.unmodifiableMap(options); + } } diff --git a/jdk/src/java.base/share/classes/jdk/net/package-info.java b/jdk/src/jdk.net/share/classes/jdk/net/package-info.java similarity index 100% rename from jdk/src/java.base/share/classes/jdk/net/package-info.java rename to jdk/src/jdk.net/share/classes/jdk/net/package-info.java diff --git a/jdk/src/jdk.net/share/classes/module-info.java b/jdk/src/jdk.net/share/classes/module-info.java new file mode 100644 index 00000000000..95fb57915a8 --- /dev/null +++ b/jdk/src/jdk.net/share/classes/module-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module jdk.net { + exports jdk.net; +} + diff --git a/jdk/src/java.base/windows/native/libnet/ExtendedOptionsImpl.c b/jdk/src/jdk.net/solaris/classes/jdk/net/SolarisSocketOptions.java similarity index 52% rename from jdk/src/java.base/windows/native/libnet/ExtendedOptionsImpl.c rename to jdk/src/jdk.net/solaris/classes/jdk/net/SolarisSocketOptions.java index 2bd955cd13e..1381f22014b 100644 --- a/jdk/src/java.base/windows/native/libnet/ExtendedOptionsImpl.c +++ b/jdk/src/jdk.net/solaris/classes/jdk/net/SolarisSocketOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,43 +23,34 @@ * questions. */ -#include -#include +package jdk.net; -#include "net_util.h" +import java.net.SocketException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; -/* - * Class: sun_net_ExtendedOptionsImpl - * Method: init - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init - (JNIEnv *env, jclass UNUSED) -{ -} - -/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */ - -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); -} - -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); -} - -static jboolean flowSupported0() { - return JNI_FALSE; -} - -JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported - (JNIEnv *env, jclass UNUSED) -{ - return JNI_FALSE; +class SolarisSocketOptions extends PlatformSocketOptions { + + public SolarisSocketOptions() { } + + @Override native int setFlowOption(int fd, int priority, long bandwidth) + throws SocketException; + + @Override native int getFlowOption(int fd, SocketFlow f) + throws SocketException; + + @Override native boolean flowSupported(); + + private static native void init(); + + static { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + System.loadLibrary("extnet"); + return null; + } + }); + init(); + } } diff --git a/jdk/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c b/jdk/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c new file mode 100644 index 00000000000..96d6ed96088 --- /dev/null +++ b/jdk/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + + +#include "SolarisSocketOptions.h" + +static jfieldID sf_priority; +static jfieldID sf_bandwidth; + +static int initialized = 0; + +/* + * Class: jdk_net_SolarisSocketOptions + * Method: init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_jdk_net_SolarisSocketOptions_init + (JNIEnv *env, jclass unused) +{ + if (!initialized) { + jclass c = (*env)->FindClass(env, "jdk/net/SocketFlow"); + CHECK_NULL(c); + sf_priority = (*env)->GetFieldID(env, c, "priority", "I"); + CHECK_NULL(sf_priority); + sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J"); + CHECK_NULL(sf_bandwidth); + initialized = 1; + } +} + +/** Return the Status value. */ +static jint toStatus(int errval) +{ + switch (errval) { + case 0: return jdk_net_SocketFlow_OK_VALUE; + case EPERM: return jdk_net_SocketFlow_NO_PERMISSION_VALUE; + case ENOTCONN: return jdk_net_SocketFlow_NOT_CONNECTED_VALUE; + case EOPNOTSUPP: return jdk_net_SocketFlow_NOT_SUPPORTED_VALUE; + case EALREADY: return jdk_net_SocketFlow_ALREADY_CREATED_VALUE; + case EINPROGRESS: return jdk_net_SocketFlow_IN_PROGRESS_VALUE; + default: return jdk_net_SocketFlow_OTHER_VALUE; + } +} + +void throwByNameWithLastError + (JNIEnv *env, const char *name, const char *defaultDetail) +{ + char defaultMsg[255]; + sprintf(defaultMsg, "errno: %d, %s", errno, defaultDetail); + JNU_ThrowByNameWithLastError(env, name, defaultMsg); +} + +/* + * Class: jdk_net_SolarisSocketOptions + * Method: setFlowOption0 + * Signature: (IIJ)I + */ +JNIEXPORT jint JNICALL Java_jdk_net_SolarisSocketOptions_setFlowOption + (JNIEnv *env, jobject unused, jint fd, jint priority, jlong bandwidth) +{ + int rv; + sock_flow_props_t props; + memset(&props, 0, sizeof(props)); + props.sfp_version = SOCK_FLOW_PROP_VERSION1; + + if (priority != jdk_net_SocketFlow_UNSET) { + props.sfp_mask |= SFP_PRIORITY; + props.sfp_priority = priority; + } + if (bandwidth > jdk_net_SocketFlow_UNSET) { + props.sfp_mask |= SFP_MAXBW; + props.sfp_maxbw = (uint64_t) bandwidth; + } + + rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); + + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else if (errno == EACCES || errno == EPERM) { + JNU_ThrowByName(env, "java/net/SocketException", "Permission denied"); + } else { + throwByNameWithLastError(env, "java/net/SocketException", + "set option SO_FLOW_SLA failed"); + } + return 0; + } + return toStatus(props.sfp_status); +} + +/* + * Class: jdk_net_SolarisSocketOptions + * Method: getFlowOption0 + * Signature: (ILjdk/net/SocketFlow;)I + */ +JNIEXPORT jint JNICALL Java_jdk_net_SolarisSocketOptions_getFlowOption + (JNIEnv *env, jobject unused, jint fd, jobject flow) +{ + sock_flow_props_t props; + socklen_t sz = sizeof(props); + + int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz); + + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else if (errno == EACCES || errno == EPERM) { + JNU_ThrowByName(env, "java/net/SocketException", "Permission denied"); + } else { + throwByNameWithLastError(env, "java/net/SocketException", + "get option SO_FLOW_SLA failed"); + } + return -1; + } + /* first check status to see if flow exists */ + if (props.sfp_status == 0) { /* OK */ + /* can set the other fields now */ + if (props.sfp_mask & SFP_PRIORITY) { + (*env)->SetIntField(env, flow, sf_priority, props.sfp_priority); + } + if (props.sfp_mask & SFP_MAXBW) { + (*env)->SetLongField(env, flow, sf_bandwidth, + (jlong)props.sfp_maxbw); + } + } + return toStatus(props.sfp_status); +} + +JNIEXPORT jboolean JNICALL Java_jdk_net_SolarisSocketOptions_flowSupported + (JNIEnv *env, jobject unused) +{ + /* Do a simple dummy call, and try to figure out from that */ + sock_flow_props_t props; + int rv, s; + + s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s < 0) { + return JNI_FALSE; + } + memset(&props, 0, sizeof(props)); + props.sfp_version = SOCK_FLOW_PROP_VERSION1; + props.sfp_mask |= SFP_PRIORITY; + props.sfp_priority = SFP_PRIO_NORMAL; + rv = setsockopt(s, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); + if (rv != 0 && errno == ENOPROTOOPT) { + rv = JNI_FALSE; + } else { + rv = JNI_TRUE; + } + close(s); + return rv; +} diff --git a/jdk/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h b/jdk/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h new file mode 100644 index 00000000000..81c65544680 --- /dev/null +++ b/jdk/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +#ifndef SOLARIS_SOCKET_OPTIONS_H +#define SOLARIS_SOCKET_OPTIONS_H + +#include +#include +#include +#include +#include + +#include "jni_util.h" +#include "jdk_net_SocketFlow.h" +#include "SolarisSocketOptions.h" +#include "jdk_net_SolarisSocketOptions.h" + +#ifndef SO_FLOW_SLA +#define SO_FLOW_SLA 0x1018 + +#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 +#pragma pack(4) +#endif + +/* + * Used with the setsockopt(SO_FLOW_SLA, ...) call to set + * per socket service level properties. + * When the application uses per-socket API, we will enforce the properties + * on both outbound and inbound packets. + * + * For now, only priority and maxbw are supported in SOCK_FLOW_PROP_VERSION1. + */ +typedef struct sock_flow_props_s { + int sfp_version; + uint32_t sfp_mask; + int sfp_priority; /* flow priority */ + uint64_t sfp_maxbw; /* bandwidth limit in bps */ + int sfp_status; /* flow create status for getsockopt */ +} sock_flow_props_t; + +#define SOCK_FLOW_PROP_VERSION1 1 + +/* bit mask values for sfp_mask */ +#define SFP_MAXBW 0x00000001 /* Flow Bandwidth Limit */ +#define SFP_PRIORITY 0x00000008 /* Flow priority */ + +/* possible values for sfp_priority */ +#define SFP_PRIO_NORMAL 1 +#define SFP_PRIO_HIGH 2 + +#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 +#pragma pack() +#endif /* _LONG_LONG_ALIGNMENT */ + +#endif /* SO_FLOW_SLA */ + +#endif /* SOLARIS_SOCKET_OPTIONS_H */ diff --git a/jdk/src/jdk.policytool/share/classes/module-info.java b/jdk/src/jdk.policytool/share/classes/module-info.java index aedfc91554a..f972e1cd15a 100644 --- a/jdk/src/jdk.policytool/share/classes/module-info.java +++ b/jdk/src/jdk.policytool/share/classes/module-info.java @@ -28,6 +28,7 @@ module jdk.policytool { requires java.logging; requires java.management; requires java.sql; + requires jdk.net; requires java.security.jgss; requires jdk.security.jgss; } diff --git a/jdk/test/java/net/SocketOption/OptionsTest.java b/jdk/test/java/net/SocketOption/OptionsTest.java index 5b109d533ac..81f33f73b9f 100644 --- a/jdk/test/java/net/SocketOption/OptionsTest.java +++ b/jdk/test/java/net/SocketOption/OptionsTest.java @@ -23,11 +23,13 @@ /* * @test - * @bug 8036979 8072384 + * @bug 8036979 8072384 8044773 * @run main/othervm -Xcheck:jni OptionsTest * @run main/othervm -Xcheck:jni -Djava.net.preferIPv4Stack=true OptionsTest + * @run main/othervm -Djdk.launcher.limitmods=java.base OptionsTest */ +import java.lang.reflect.Method; import java.net.*; import java.util.*; @@ -43,7 +45,7 @@ public class OptionsTest { } Object option; Object testValue; - }; + } // The tests set the option using the new API, read back the set value // which could be diferent, and then use the legacy get API to check @@ -223,8 +225,7 @@ public class OptionsTest { } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); } else if (option.equals(StandardSocketOptions.IP_TOS)) { - return Integer.valueOf(jdk.net.Sockets.getOption( - socket, StandardSocketOptions.IP_TOS)); + return getServerSocketTrafficClass(socket); } else { throw new RuntimeException("unexecpted socket option"); } @@ -281,4 +282,20 @@ public class OptionsTest { doDgSocketTests(); doMcSocketTests(); } + + // Reflectively access jdk.net.Sockets.getOption so that the test can run + // without the jdk.net module. + static Object getServerSocketTrafficClass(ServerSocket ss) throws Exception { + try { + Class c = Class.forName("jdk.net.Sockets"); + Method m = c.getDeclaredMethod("getOption", ServerSocket.class, SocketOption.class); + return m.invoke(null, ss, StandardSocketOptions.IP_TOS); + } catch (ClassNotFoundException e) { + // Ok, jdk.net module not present, just fall back + System.out.println("jdk.net module not present, falling back."); + return Integer.valueOf(ss.getOption(StandardSocketOptions.IP_TOS)); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } } diff --git a/jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java b/jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java index 074f7644b9d..0ab43f6ff27 100644 --- a/jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java +++ b/jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java @@ -21,34 +21,48 @@ * questions. */ -import jdk.net.ExtendedSocketOptions; - import java.io.IOException; +import java.lang.reflect.Field; import java.net.*; +import java.util.ArrayList; +import java.util.List; /* * @test - * @bug 8143554 - * @run main UnsupportedOptionsTest + * @bug 8143554 8044773 * @summary Test checks that UnsupportedOperationException for unsupported * SOCKET_OPTIONS is thrown by both getOption() and setOption() methods. + * @run main UnsupportedOptionsTest + * @run main/othervm -Djdk.launcher.limitmods=java.base UnsupportedOptionsTest */ + public class UnsupportedOptionsTest { - private static final SocketOption[] SOCKET_OPTIONS = { - StandardSocketOptions.IP_MULTICAST_IF, - StandardSocketOptions.IP_MULTICAST_LOOP, - StandardSocketOptions.IP_MULTICAST_TTL, - StandardSocketOptions.IP_TOS, - StandardSocketOptions.SO_BROADCAST, - StandardSocketOptions.SO_KEEPALIVE, - StandardSocketOptions.SO_LINGER, - StandardSocketOptions.SO_RCVBUF, - StandardSocketOptions.SO_REUSEADDR, - StandardSocketOptions.SO_SNDBUF, - StandardSocketOptions.TCP_NODELAY, - ExtendedSocketOptions.SO_FLOW_SLA - }; + private static final List> socketOptions = new ArrayList<>(); + + static { + socketOptions.add(StandardSocketOptions.IP_MULTICAST_IF); + socketOptions.add(StandardSocketOptions.IP_MULTICAST_LOOP); + socketOptions.add(StandardSocketOptions.IP_MULTICAST_TTL); + socketOptions.add(StandardSocketOptions.IP_TOS); + socketOptions.add(StandardSocketOptions.SO_BROADCAST); + socketOptions.add(StandardSocketOptions.SO_KEEPALIVE); + socketOptions.add(StandardSocketOptions.SO_LINGER); + socketOptions.add(StandardSocketOptions.SO_RCVBUF); + socketOptions.add(StandardSocketOptions.SO_REUSEADDR); + socketOptions.add(StandardSocketOptions.SO_SNDBUF); + socketOptions.add(StandardSocketOptions.TCP_NODELAY); + + try { + Class c = Class.forName("jdk.net.ExtendedSocketOptions"); + Field field = c.getField("SO_FLOW_SLA"); + socketOptions.add((SocketOption)field.get(null)); + } catch (ClassNotFoundException e) { + // ignore, jdk.net module not present + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } public static void main(String[] args) throws IOException { Socket s = new Socket(); @@ -56,7 +70,7 @@ public class UnsupportedOptionsTest { DatagramSocket ds = new DatagramSocket(); MulticastSocket ms = new MulticastSocket(); - for (SocketOption option : SOCKET_OPTIONS) { + for (SocketOption option : socketOptions) { if (!s.supportedOptions().contains(option)) { testUnsupportedSocketOption(s, option); } diff --git a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java index 40aef3282ac..00281647f17 100644 --- a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java @@ -22,8 +22,10 @@ */ /* @test - * @bug 4640544 + * @bug 4640544 8044773 * @summary Unit test for setOption/getOption/options methods + * @run main SocketOptionTests + * @run main/othervm -Djdk.launcher.limitmods=java.base SocketOptionTests */ import java.nio.*; diff --git a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java index 0a3aa9dee32..a0b2b6a8e82 100644 --- a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java @@ -22,9 +22,11 @@ */ /* @test - * @bug 4640544 + * @bug 4640544 8044773 * @summary Unit test for ServerSocketChannel setOption/getOption/options * methods. + * @run main SocketOptionTests + * @run main/othervm -Djdk.launcher.limitmods=java.base SocketOptionTests */ import java.nio.*; diff --git a/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java index f1cb496afea..74f87c71623 100644 --- a/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java @@ -22,9 +22,11 @@ */ /* @test - * @bug 4640544 + * @bug 4640544 8044773 * @summary Unit test to check SocketChannel setOption/getOption/options * methods. + * @run main SocketOptionTests + * @run main/othervm -Djdk.launcher.limitmods=java.base SocketOptionTests */ import java.nio.*; diff --git a/jdk/test/jdk/net/SocketFlow/SocketFlowBasic.java b/jdk/test/jdk/net/SocketFlow/SocketFlowBasic.java new file mode 100644 index 00000000000..ca02ad931d6 --- /dev/null +++ b/jdk/test/jdk/net/SocketFlow/SocketFlowBasic.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8765432 + * @summary Basic test for SocketFlow API + * @run testng SocketFlowBasic + */ + +import jdk.net.SocketFlow; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static jdk.net.SocketFlow.*; +import static org.testng.Assert.*; + +public class SocketFlowBasic { + + @DataProvider + public Object[][] validPriorities() { + return new Object[][] { {HIGH_PRIORITY}, {NORMAL_PRIORITY} }; + } + + @Test(dataProvider = "validPriorities") + public void priority(long validPriority) { + SocketFlow flow = SocketFlow.create(); + flow.bandwidth(validPriority); + long bandwidth = flow.bandwidth(); + assertTrue(bandwidth == validPriority, "Expected " + validPriority + ", got" + bandwidth); + } + + @DataProvider + public Object[][] invalidPriorities() { + return new Object[][] { {HIGH_PRIORITY+10}, {NORMAL_PRIORITY-10000} }; + } + + @Test(dataProvider = "invalidPriorities", expectedExceptions = IllegalArgumentException.class) + public void priority(int invalidPriority) { + SocketFlow flow = SocketFlow.create(); + flow.priority(invalidPriority); + } + + @DataProvider + public Object[][] positiveBandwidth() { + return new Object[][] { {0}, {100}, {Integer.MAX_VALUE}, {Long.MAX_VALUE} }; + } + + @Test(dataProvider = "positiveBandwidth") + public void bandwidth(long posBandwidth) { + SocketFlow flow = SocketFlow.create(); + flow.bandwidth(posBandwidth); + long bandwidth = flow.bandwidth(); + assertTrue(bandwidth == posBandwidth, "Expected " + posBandwidth + ", got" + bandwidth); + } + + + @DataProvider + public Object[][] negativeBandwidth() { + return new Object[][] { {-1}, {-100}, {Integer.MIN_VALUE}, {Long.MIN_VALUE} }; + } + + @Test(dataProvider = "negativeBandwidth", expectedExceptions = IllegalArgumentException.class) + public void invalidBandwidth(long negBandwidth) { + SocketFlow flow = SocketFlow.create(); + flow.bandwidth(negBandwidth); + } + + @Test + public void status() { + SocketFlow flow = SocketFlow.create(); + assertTrue(flow.status() == Status.NO_STATUS); + } +} diff --git a/jdk/test/jdk/net/Sockets/Test.java b/jdk/test/jdk/net/Sockets/Test.java index bf3758c5bae..8bb03c54919 100644 --- a/jdk/test/jdk/net/Sockets/Test.java +++ b/jdk/test/jdk/net/Sockets/Test.java @@ -23,8 +23,9 @@ /* * @test - * @bug 8032808 - * @run main/othervm -Xcheck:jni Test + * @bug 8032808 8044773 + * @modules jdk.net + * @run main/othervm -Xcheck:jni Test success * @run main/othervm/policy=policy.fail -Xcheck:jni Test fail * @run main/othervm/policy=policy.success -Xcheck:jni Test success */ @@ -35,15 +36,13 @@ import java.nio.channels.*; import java.util.concurrent.*; import java.util.Set; import jdk.net.*; +import static java.lang.System.out; public class Test { - static boolean security; - static boolean success; + interface Runner { void run() throws Exception; } - interface Runner { - public void run() throws Exception; - } + static boolean expectSuccess; public static void main(String[] args) throws Exception { @@ -52,95 +51,107 @@ public class Test { Sockets.supportedOptions(Socket.class); - security = System.getSecurityManager() != null; - success = security && args[0].equals("success"); + expectSuccess = args[0].equals("success"); // Main thing is to check for JNI problems // Doesn't matter if current system does not support the option // and currently setting the option with the loopback interface // doesn't work either - System.out.println ("Security Manager enabled: " + security); - if (security) { - System.out.println ("Success expected: " + success); + boolean sm = System.getSecurityManager() != null; + out.println("Security Manager enabled: " + sm); + out.println("Success expected: " + expectSuccess); + + SocketFlow flowIn = SocketFlow.create() + .bandwidth(1000) + .priority(SocketFlow.HIGH_PRIORITY); + + try (ServerSocket ss = new ServerSocket(0); + DatagramSocket dg = new DatagramSocket(0)) { + + int tcp_port = ss.getLocalPort(); + final InetAddress loop = InetAddress.getByName("127.0.0.1"); + final InetSocketAddress loopad = new InetSocketAddress(loop, tcp_port); + + final int udp_port = dg.getLocalPort(); + + // If option not available, end test + Set> options = dg.supportedOptions(); + if (!options.contains(ExtendedSocketOptions.SO_FLOW_SLA)) { + System.out.println("SO_FLOW_SLA not supported"); + return; + } + + final Socket s = new Socket("127.0.0.1", tcp_port); + final SocketChannel sc = SocketChannel.open(); + sc.connect(new InetSocketAddress("127.0.0.1", tcp_port)); + + doTest("Sockets.setOption Socket", () -> { + out.println(flowIn); + Sockets.setOption(s, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + out.println(flowIn); + }); + doTest("Sockets.getOption Socket",() -> { + Sockets.getOption(s, ExtendedSocketOptions.SO_FLOW_SLA); + out.println(flowIn); + }); + doTest("Sockets.setOption SocketChannel",() -> + sc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn) + ); + doTest("Sockets.getOption SocketChannel",() -> + sc.getOption(ExtendedSocketOptions.SO_FLOW_SLA) + ); + doTest("Sockets.setOption DatagramSocket",() -> { + try (DatagramSocket dg1 = new DatagramSocket(0)) { + dg1.connect(loop, udp_port); + Sockets.setOption(dg1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + } + }); + doTest("Sockets.setOption DatagramSocket 2", () -> { + try (DatagramChannel dg2 = DatagramChannel.open()) { + dg2.bind(new InetSocketAddress(loop, 0)); + dg2.connect(new InetSocketAddress(loop, udp_port)); + dg2.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + } + }); + doTest("Sockets.setOption MulticastSocket", () -> { + try (MulticastSocket mc1 = new MulticastSocket(0)) { + mc1.connect(loop, udp_port); + Sockets.setOption(mc1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + } + }); + doTest("Sockets.setOption AsynchronousSocketChannel", () -> { + try (AsynchronousSocketChannel asc = AsynchronousSocketChannel.open()) { + Future f = asc.connect(loopad); + f.get(); + asc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + } + }); } - - final SocketFlow flowIn = SocketFlow.create() - .bandwidth(1000) - .priority(SocketFlow.HIGH_PRIORITY); - - ServerSocket ss = new ServerSocket(0); - int tcp_port = ss.getLocalPort(); - final InetAddress loop = InetAddress.getByName("127.0.0.1"); - final InetSocketAddress loopad = new InetSocketAddress(loop, tcp_port); - - DatagramSocket dg = new DatagramSocket(0); - final int udp_port = dg.getLocalPort(); - - // If option not available, end test - Set> options = dg.supportedOptions(); - if (!options.contains(ExtendedSocketOptions.SO_FLOW_SLA)) { - System.out.println("SO_FLOW_SLA not supported"); - return; - } - - final Socket s = new Socket("127.0.0.1", tcp_port); - final SocketChannel sc = SocketChannel.open(); - sc.connect (new InetSocketAddress("127.0.0.1", tcp_port)); - - doTest(()->{ - Sockets.setOption(s, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - Sockets.getOption(s, ExtendedSocketOptions.SO_FLOW_SLA); - }); - doTest(()->{ - sc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - sc.getOption(ExtendedSocketOptions.SO_FLOW_SLA); - }); - doTest(()->{ - DatagramSocket dg1 = new DatagramSocket(0); - dg1.connect(loop, udp_port); - Sockets.setOption(dg1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - DatagramChannel dg2 = DatagramChannel.open(); - dg2.bind(new InetSocketAddress(loop, 0)); - dg2.connect(new InetSocketAddress(loop, udp_port)); - dg2.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - MulticastSocket mc1 = new MulticastSocket(0); - mc1.connect(loop, udp_port); - Sockets.setOption(mc1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - AsynchronousSocketChannel asc = AsynchronousSocketChannel.open(); - Future f = asc.connect(loopad); - f.get(); - asc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); } - static void doTest(Runner func) throws Exception { + static void doTest(String message, Runner func) throws Exception { + out.println(message); try { func.run(); - if (security && !success) { - throw new RuntimeException("Test failed"); + if (expectSuccess) { + out.println("Completed as expected"); + } else { + throw new RuntimeException("Operation succeeded, but expected SecurityException"); } } catch (SecurityException e) { - if (success) { - throw new RuntimeException("Test failed"); + if (expectSuccess) { + throw new RuntimeException("Unexpected SecurityException", e); + } else { + out.println("Caught expected: " + e); } } catch (UnsupportedOperationException e) { - System.out.println (e); + System.out.println(e); } catch (IOException e) { // Probably a permission error, but we're not // going to check unless a specific permission exception // is defined. - System.out.println (e); + System.out.println(e); } } } From 2ef07f57fa9561cee6ed0155d52b5172650b1076 Mon Sep 17 00:00:00 2001 From: Alexander Kouznetsov Date: Wed, 27 Apr 2016 17:47:17 -0700 Subject: [PATCH 165/222] 8154381: SwingSet tests are not auto closed in jtreg Reviewed-by: alexsch --- .../nbproject/genfiles.properties | 2 +- .../nbproject/project.properties | 2 +- .../client_sanity/nbproject/project.xml | 2 +- .../src/ButtonDemoScreenshotTest.java | 24 ++-- .../client/SwingSet/src/ButtonDemoTest.java | 44 ++++---- .../client/SwingSet/src/ComboBoxDemoTest.java | 19 ++-- .../client/SwingSet/src/ListDemoTest.java | 83 +++++++------- .../SwingSet/src/OptionPaneDemoTest.java | 31 +++--- .../SwingSet/src/ProgressBarDemoTest.java | 27 ++--- .../SwingSet/src/ScrollPaneDemoTest.java | 105 +++++++++--------- .../client/SwingSet/src/SpinnerDemoTest.java | 20 ++-- .../SwingSet/src/SplitPaneDemoTest.java | 38 ++++--- .../SwingSet/src/TabbedPaneDemoTest.java | 18 +-- .../SwingSet/src/TextFieldDemoTest.java | 18 +-- .../SwingSet/src/ToggleButtonDemoTest.java | 58 +++++----- .../client/SwingSet/src/TreeDemoTest.java | 81 +++++++------- .../client/SwingSet/src/WindowDemoTest.java | 32 +++--- .../src/org/jemmy2ext/JemmyExt.java | 23 ++-- .../src/org/jtregext/GuiTestListener.java | 72 ++++++++++++ .../demos/tabbedpane/TabbedPaneDemo.java | 6 +- 20 files changed, 395 insertions(+), 310 deletions(-) rename jdk/test/sanity/client/lib/{Jemmy2Ext => Extensions}/src/org/jemmy2ext/JemmyExt.java (97%) create mode 100644 jdk/test/sanity/client/lib/Extensions/src/org/jtregext/GuiTestListener.java diff --git a/jdk/make/netbeans/client_sanity/nbproject/genfiles.properties b/jdk/make/netbeans/client_sanity/nbproject/genfiles.properties index fc956fd5f2e..48d69459d3f 100644 --- a/jdk/make/netbeans/client_sanity/nbproject/genfiles.properties +++ b/jdk/make/netbeans/client_sanity/nbproject/genfiles.properties @@ -3,6 +3,6 @@ build.xml.script.CRC32=f902e8b8 build.xml.stylesheet.CRC32=8064a381@1.75.2.48 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=55414227 +nbproject/build-impl.xml.data.CRC32=16caf60f nbproject/build-impl.xml.script.CRC32=c12f9d04 nbproject/build-impl.xml.stylesheet.CRC32=05530350@1.79.1.48 diff --git a/jdk/make/netbeans/client_sanity/nbproject/project.properties b/jdk/make/netbeans/client_sanity/nbproject/project.properties index a43ee024fd8..f3e9384ce3f 100644 --- a/jdk/make/netbeans/client_sanity/nbproject/project.properties +++ b/jdk/make/netbeans/client_sanity/nbproject/project.properties @@ -76,4 +76,4 @@ source.encoding=UTF-8 src.src.dir=..\\..\\..\\test\\sanity\\client\\SwingSet\\src src.src2.dir=..\\..\\..\\test\\sanity\\client\\lib\\SwingSet3\\src src.src3.dir=..\\..\\..\\test\\sanity\\client\\lib\\jemmy\\src -src.src4.dir=..\\..\\..\\test\\sanity\\client\\lib\\Jemmy2Ext\\src +src.src4.dir=..\\..\\..\\test\\sanity\\client\\lib\\Extensions\\src diff --git a/jdk/make/netbeans/client_sanity/nbproject/project.xml b/jdk/make/netbeans/client_sanity/nbproject/project.xml index fccac4ecf31..554dc3073d5 100644 --- a/jdk/make/netbeans/client_sanity/nbproject/project.xml +++ b/jdk/make/netbeans/client_sanity/nbproject/project.xml @@ -6,7 +6,7 @@ SanityTests - + diff --git a/jdk/test/sanity/client/SwingSet/src/ButtonDemoScreenshotTest.java b/jdk/test/sanity/client/SwingSet/src/ButtonDemoScreenshotTest.java index b6959ac150a..61022339fc2 100644 --- a/jdk/test/sanity/client/SwingSet/src/ButtonDemoScreenshotTest.java +++ b/jdk/test/sanity/client/SwingSet/src/ButtonDemoScreenshotTest.java @@ -21,6 +21,8 @@ * questions. */ +import com.sun.swingset3.demos.button.ButtonDemo; +import org.jtregext.GuiTestListener; import java.awt.Point; import java.awt.Robot; import java.awt.event.InputEvent; @@ -32,6 +34,7 @@ import org.netbeans.jemmy.operators.JFrameOperator; import static org.jemmy2ext.JemmyExt.*; import org.testng.annotations.Test; import static com.sun.swingset3.demos.button.ButtonDemo.*; +import org.testng.annotations.Listeners; /* * @test @@ -41,31 +44,30 @@ import static com.sun.swingset3.demos.button.ButtonDemo.*; * image is different from initial button image. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.button.ButtonDemo * @run testng ButtonDemoScreenshotTest */ +@Listeners(GuiTestListener.class) public class ButtonDemoScreenshotTest { private static final int BUTTON_COUNT = 6; // TODO: Decide about "open browser" buttons (value was 8 originally) @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - Robot rob = new Robot(); + Robot rob = new Robot(); - new ClassReference(com.sun.swingset3.demos.button.ButtonDemo.class.getCanonicalName()).startApplication(); + new ClassReference(ButtonDemo.class.getCanonicalName()).startApplication(); - JFrameOperator mainFrame = new JFrameOperator(DEMO_TITLE); - waitImageIsStill(rob, mainFrame); + JFrameOperator mainFrame = new JFrameOperator(DEMO_TITLE); + waitImageIsStill(rob, mainFrame); - // Check all the buttons - for (int i = 0; i < BUTTON_COUNT; i++) { - checkButton(mainFrame, i, rob); - } - }); + // Check all the buttons + for (int i = 0; i < BUTTON_COUNT; i++) { + checkButton(mainFrame, i, rob); + } } public void checkButton(JFrameOperator jfo, int i, Robot rob) { diff --git a/jdk/test/sanity/client/SwingSet/src/ButtonDemoTest.java b/jdk/test/sanity/client/SwingSet/src/ButtonDemoTest.java index 3d0d8f1afea..da540dbb648 100644 --- a/jdk/test/sanity/client/SwingSet/src/ButtonDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/ButtonDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.JHyperlink; import com.sun.swingset3.demos.button.ButtonDemo; import java.util.concurrent.ArrayBlockingQueue; @@ -38,7 +39,7 @@ import org.netbeans.jemmy.operators.JFrameOperator; import static com.sun.swingset3.demos.button.ButtonDemo.*; import org.jemmy2ext.JemmyExt; import org.jemmy2ext.JemmyExt.MultiThreadedTryCatch; -import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; +import org.testng.annotations.Listeners; /* * @test @@ -48,12 +49,13 @@ import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; * on buttons before and after click. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.button.ButtonDemo * @run testng ButtonDemoTest */ +@Listeners(GuiTestListener.class) public class ButtonDemoTest { private static final String[] BUTTON_TEXT_AFTER = { @@ -92,34 +94,30 @@ public class ButtonDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { + new ClassReference(ButtonDemo.class.getCanonicalName()).startApplication(); - new ClassReference(ButtonDemo.class.getCanonicalName()).startApplication(); + JFrameOperator mainFrame = new JFrameOperator(DEMO_TITLE); + mainFrame.setComparator(EXACT_STRING_COMPARATOR); - JFrameOperator mainFrame = new JFrameOperator(DEMO_TITLE); - mainFrame.setComparator(EXACT_STRING_COMPARATOR); + // Check all the buttons + for (int i = 0; i < BUTTON_TOOLTIP.length; i++) { + String tooltip = BUTTON_TOOLTIP[i]; - // Check all the buttons - for (int i = 0; i < BUTTON_TOOLTIP.length; i++) { - String tooltip = BUTTON_TOOLTIP[i]; + JButtonOperator button = new JButtonOperator(mainFrame, new ByToolTipChooser(tooltip)); - JButtonOperator button = new JButtonOperator(mainFrame, new ByToolTipChooser(tooltip)); + assertEquals(BUTTON_TEXT_BEFORE[i], button.getText()); - assertEquals(BUTTON_TEXT_BEFORE[i], button.getText()); - - // Two buttons are hyperlinks, we don't want to click them - if (!button.getSource().getClass().equals(JHyperlink.class)) { - checkButton(button); - } - - if (BUTTON_TEXT_AFTER.length > i) { - assertEquals(BUTTON_TEXT_AFTER[i], button.getText()); - } else { - assertEquals(BUTTON_TEXT_BEFORE[i], button.getText()); - } + // Two buttons are hyperlinks, we don't want to click them + if (!button.getSource().getClass().equals(JHyperlink.class)) { + checkButton(button); } - }); + if (BUTTON_TEXT_AFTER.length > i) { + assertEquals(BUTTON_TEXT_AFTER[i], button.getText()); + } else { + assertEquals(BUTTON_TEXT_BEFORE[i], button.getText()); + } + } } private void checkButton(JButtonOperator button) throws Exception { diff --git a/jdk/test/sanity/client/SwingSet/src/ComboBoxDemoTest.java b/jdk/test/sanity/client/SwingSet/src/ComboBoxDemoTest.java index 303bbd681f1..790bc9d3711 100644 --- a/jdk/test/sanity/client/SwingSet/src/ComboBoxDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/ComboBoxDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.combobox.ComboBoxDemo; import static org.testng.AssertJUnit.*; import org.testng.annotations.Test; @@ -28,7 +29,7 @@ import org.netbeans.jemmy.ClassReference; import org.netbeans.jemmy.operators.JComboBoxOperator; import org.netbeans.jemmy.operators.JFrameOperator; import static com.sun.swingset3.demos.combobox.ComboBoxDemo.*; -import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; +import org.testng.annotations.Listeners; /* * @test @@ -37,12 +38,13 @@ import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; * each value of each ComboBox. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.combobox.ComboBoxDemo * @run testng ComboBoxDemoTest */ +@Listeners(GuiTestListener.class) public class ComboBoxDemoTest { private static enum ComboBoxInfo { @@ -61,14 +63,13 @@ public class ComboBoxDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(ComboBoxDemo.class.getCanonicalName()).startApplication(); - JFrameOperator frame = new JFrameOperator(DEMO_TITLE); - for (ComboBoxInfo comboBoxInfo : ComboBoxInfo.values()) { - comboBoxChecker(frame, comboBoxInfo); - } - }); + new ClassReference(ComboBoxDemo.class.getCanonicalName()).startApplication(); + + JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + for (ComboBoxInfo comboBoxInfo : ComboBoxInfo.values()) { + comboBoxChecker(frame, comboBoxInfo); + } } private void comboBoxChecker(JFrameOperator jfo, ComboBoxInfo comboBoxInfo) { diff --git a/jdk/test/sanity/client/SwingSet/src/ListDemoTest.java b/jdk/test/sanity/client/SwingSet/src/ListDemoTest.java index c24399e526b..c977385b9bb 100644 --- a/jdk/test/sanity/client/SwingSet/src/ListDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/ListDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.list.ListDemo; import static com.sun.swingset3.demos.list.ListDemo.DEMO_TITLE; import static org.testng.AssertJUnit.*; @@ -30,7 +31,7 @@ import org.netbeans.jemmy.ClassReference; import org.netbeans.jemmy.operators.JCheckBoxOperator; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JListOperator; -import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; +import org.testng.annotations.Listeners; /* * @test @@ -40,64 +41,64 @@ import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; * list. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.list.ListDemo * @run testng ListDemoTest */ +@Listeners(GuiTestListener.class) public class ListDemoTest { private static final int CHECKBOX_COUNT = 50; @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(ListDemo.class.getCanonicalName()).startApplication(); - JFrameOperator frame = new JFrameOperator(DEMO_TITLE); - JListOperator listOp = new JListOperator(frame); + new ClassReference(ListDemo.class.getCanonicalName()).startApplication(); - // Check *NO* Prefix and Suffixes Marked - for (int i = 0; i < CHECKBOX_COUNT; i++) { - JCheckBoxOperator checkBox = getJCheckBoxOperator(frame, i); + JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + JListOperator listOp = new JListOperator(frame); + + // Check *NO* Prefix and Suffixes Marked + for (int i = 0; i < CHECKBOX_COUNT; i++) { + JCheckBoxOperator checkBox = getJCheckBoxOperator(frame, i); + checkBox.changeSelection(false); + } + System.out.println("######## Number of Items = " + listOp.getModel().getSize()); + assertEquals("Select None number of items is correct", 0, listOp.getModel().getSize()); + + // Check *ALL* Prefix and Suffixes Marked + for (int i = 0; i < CHECKBOX_COUNT; i++) { + JCheckBoxOperator checkBox = getJCheckBoxOperator(frame, i); + checkBox.changeSelection(true); + } + System.out.println("######## Number of Items = " + listOp.getModel().getSize()); + assertEquals("Select All number of items is correct", CHECKBOX_COUNT / 2 * CHECKBOX_COUNT / 2, listOp.getModel().getSize()); + + // Check *ALL* Prefix and *NO* Suffixes Marked + for (int i = 0; i < CHECKBOX_COUNT; i++) { + JCheckBoxOperator checkBox = getJCheckBoxOperator(frame, i); + if (i < CHECKBOX_COUNT / 2) { + checkBox.changeSelection(true); + } else { checkBox.changeSelection(false); } - System.out.println("######## Number of Items = " + listOp.getModel().getSize()); - assertEquals("Select None number of items is correct", 0, listOp.getModel().getSize()); + } + System.out.println("######## Number of Items = " + listOp.getModel().getSize()); + assertEquals("Select All Prefixes and NO Suffixes number of items is correct", 0, listOp.getModel().getSize()); - // Check *ALL* Prefix and Suffixes Marked - for (int i = 0; i < CHECKBOX_COUNT; i++) { - JCheckBoxOperator checkBox = getJCheckBoxOperator(frame, i); + // Check *NO* Prefix and *ALL* Suffixes Marked + for (int i = 0; i < CHECKBOX_COUNT; i++) { + JCheckBoxOperator checkBox = getJCheckBoxOperator(frame, i); + if (i < CHECKBOX_COUNT / 2) { + checkBox.changeSelection(false); + } else { checkBox.changeSelection(true); } - System.out.println("######## Number of Items = " + listOp.getModel().getSize()); - assertEquals("Select All number of items is correct", CHECKBOX_COUNT / 2 * CHECKBOX_COUNT / 2, listOp.getModel().getSize()); - - // Check *ALL* Prefix and *NO* Suffixes Marked - for (int i = 0; i < CHECKBOX_COUNT; i++) { - JCheckBoxOperator checkBox = getJCheckBoxOperator(frame, i); - if (i < CHECKBOX_COUNT / 2) { - checkBox.changeSelection(true); - } else { - checkBox.changeSelection(false); - } - } - System.out.println("######## Number of Items = " + listOp.getModel().getSize()); - assertEquals("Select All Prefixes and NO Suffixes number of items is correct", 0, listOp.getModel().getSize()); - - // Check *NO* Prefix and *ALL* Suffixes Marked - for (int i = 0; i < CHECKBOX_COUNT; i++) { - JCheckBoxOperator checkBox = getJCheckBoxOperator(frame, i); - if (i < CHECKBOX_COUNT / 2) { - checkBox.changeSelection(false); - } else { - checkBox.changeSelection(true); - } - } - System.out.println("######## Number of Items = " + listOp.getModel().getSize()); - assertEquals("Select NO Prefixes and All Suffixes number of items is correct", 0, listOp.getModel().getSize()); - }); + } + System.out.println("######## Number of Items = " + listOp.getModel().getSize()); + assertEquals("Select NO Prefixes and All Suffixes number of items is correct", 0, listOp.getModel().getSize()); } private JCheckBoxOperator getJCheckBoxOperator(JFrameOperator frame, int index) { diff --git a/jdk/test/sanity/client/SwingSet/src/OptionPaneDemoTest.java b/jdk/test/sanity/client/SwingSet/src/OptionPaneDemoTest.java index 2cecfe72637..9ac377f7d2a 100644 --- a/jdk/test/sanity/client/SwingSet/src/OptionPaneDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/OptionPaneDemoTest.java @@ -21,10 +21,10 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.optionpane.OptionPaneDemo; import static com.sun.swingset3.demos.optionpane.OptionPaneDemo.*; import javax.swing.UIManager; -import static org.jemmy2ext.JemmyExt.*; import static org.testng.AssertJUnit.*; import org.testng.annotations.Test; import org.netbeans.jemmy.ClassReference; @@ -34,6 +34,7 @@ import org.netbeans.jemmy.operators.JDialogOperator; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JLabelOperator; import org.netbeans.jemmy.operators.JTextFieldOperator; +import org.testng.annotations.Listeners; /* @@ -43,12 +44,13 @@ import org.netbeans.jemmy.operators.JTextFieldOperator; * and choosing different options in them. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.optionpane.OptionPaneDemo * @run testng OptionPaneDemoTest */ +@Listeners(GuiTestListener.class) public class OptionPaneDemoTest { public static final String SOME_TEXT_TO_TYPE = "I am some text"; @@ -59,21 +61,20 @@ public class OptionPaneDemoTest { public static final String TEXT_TO_TYPE = "Hooray! I'm a textField"; public static final String NO = "No"; public static final String YES = "Yes"; - public static final String SELECT_AN__OPTION = UIManager.getString("OptionPane.titleText"); + public static final String SELECT_AN_OPTION = UIManager.getString("OptionPane.titleText"); @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(OptionPaneDemo.class.getCanonicalName()).startApplication(); - JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + new ClassReference(OptionPaneDemo.class.getCanonicalName()).startApplication(); - showInputDialog(frame); - showWarningDialog(frame); - showMessageDialog(frame); - showComponentDialog(frame); - showConfirmationDialog(frame); - }); + JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + + showInputDialog(frame); + showWarningDialog(frame); + showMessageDialog(frame); + showComponentDialog(frame); + showConfirmationDialog(frame); } public void showInputDialog(JFrameOperator jfo) throws Exception { @@ -286,7 +287,7 @@ public class OptionPaneDemoTest { { new JButtonOperator(jfo, CONFIRM_BUTTON).pushNoBlock(); - JDialogOperator jdo = new JDialogOperator(SELECT_AN__OPTION); + JDialogOperator jdo = new JDialogOperator(SELECT_AN_OPTION); new JButtonOperator(jdo, YES).pushNoBlock(); JDialogOperator jdo1 = new JDialogOperator(MESSAGE); @@ -306,7 +307,7 @@ public class OptionPaneDemoTest { { new JButtonOperator(jfo, CONFIRM_BUTTON).pushNoBlock(); - JDialogOperator jdo = new JDialogOperator(SELECT_AN__OPTION); + JDialogOperator jdo = new JDialogOperator(SELECT_AN_OPTION); new JButtonOperator(jdo, NO).pushNoBlock(); JDialogOperator jdo1 = new JDialogOperator(MESSAGE); @@ -326,7 +327,7 @@ public class OptionPaneDemoTest { { new JButtonOperator(jfo, CONFIRM_BUTTON).pushNoBlock(); - JDialogOperator jdo = new JDialogOperator(SELECT_AN__OPTION); + JDialogOperator jdo = new JDialogOperator(SELECT_AN_OPTION); assertTrue("Show Confirmation Dialog Cancel Option", jdo.isShowing()); diff --git a/jdk/test/sanity/client/SwingSet/src/ProgressBarDemoTest.java b/jdk/test/sanity/client/SwingSet/src/ProgressBarDemoTest.java index 411d05cd1b7..b705974274f 100644 --- a/jdk/test/sanity/client/SwingSet/src/ProgressBarDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/ProgressBarDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.progressbar.ProgressBarDemo; import static com.sun.swingset3.demos.progressbar.ProgressBarDemo.*; import java.awt.Component; @@ -31,7 +32,7 @@ import org.netbeans.jemmy.ComponentChooser; import org.netbeans.jemmy.operators.JButtonOperator; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JProgressBarOperator; -import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; +import org.testng.annotations.Listeners; /* * @test @@ -40,31 +41,31 @@ import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; * buttons and checking the progress bar and the buttons state. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.progressbar.ProgressBarDemo * @run testng ProgressBarDemoTest */ +@Listeners(GuiTestListener.class) public class ProgressBarDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(ProgressBarDemo.class.getCanonicalName()).startApplication(); - JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + new ClassReference(ProgressBarDemo.class.getCanonicalName()).startApplication(); - JButtonOperator startButton = new JButtonOperator(frame, START_BUTTON); - JButtonOperator stopButton = new JButtonOperator(frame, STOP_BUTTON); - JProgressBarOperator jpbo = new JProgressBarOperator(frame); + JFrameOperator frame = new JFrameOperator(DEMO_TITLE); - // Check that progress completes and corect enable/disable of start/stop buttons - checkCompleteProgress(frame, startButton, stopButton, jpbo); + JButtonOperator startButton = new JButtonOperator(frame, START_BUTTON); + JButtonOperator stopButton = new JButtonOperator(frame, STOP_BUTTON); + JProgressBarOperator jpbo = new JProgressBarOperator(frame); - // Check progess bar progression and start/stop button disabled/enabled states - checkStartStop(frame, startButton, stopButton, jpbo); - }); + // Check that progress completes and corect enable/disable of start/stop buttons + checkCompleteProgress(frame, startButton, stopButton, jpbo); + + // Check progess bar progression and start/stop button disabled/enabled states + checkStartStop(frame, startButton, stopButton, jpbo); } // Check that progress completes and corect enable/disable of start/stop buttons diff --git a/jdk/test/sanity/client/SwingSet/src/ScrollPaneDemoTest.java b/jdk/test/sanity/client/SwingSet/src/ScrollPaneDemoTest.java index bd88904f875..2023eff16a3 100644 --- a/jdk/test/sanity/client/SwingSet/src/ScrollPaneDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/ScrollPaneDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.scrollpane.ScrollPaneDemo; import static com.sun.swingset3.demos.scrollpane.ScrollPaneDemo.DEMO_TITLE; import static org.testng.AssertJUnit.*; @@ -28,7 +29,7 @@ import org.testng.annotations.Test; import org.netbeans.jemmy.ClassReference; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JScrollPaneOperator; -import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; +import org.testng.annotations.Listeners; /* * @test @@ -37,73 +38,73 @@ import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; * to left and to right and checking scroll bar values. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.scrollpane.ScrollPaneDemo * @run testng ScrollPaneDemoTest */ +@Listeners(GuiTestListener.class) public class ScrollPaneDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(ScrollPaneDemo.class.getName()).startApplication(); - JFrameOperator frame = new JFrameOperator(DEMO_TITLE); - JScrollPaneOperator jspo = new JScrollPaneOperator(frame); + new ClassReference(ScrollPaneDemo.class.getName()).startApplication(); - // Set initial scrollbar positions - int initialVerticalValue = jspo.getVerticalScrollBar().getValue(); - int initialHorizontalValue = jspo.getHorizontalScrollBar().getValue(); + JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + JScrollPaneOperator jspo = new JScrollPaneOperator(frame); - System.out.println("Initial Vertical Value = " + jspo.getVerticalScrollBar().getValue()); - System.out.println("Initial HoriZontal Value = " + jspo.getHorizontalScrollBar().getValue()); + // Set initial scrollbar positions + int initialVerticalValue = jspo.getVerticalScrollBar().getValue(); + int initialHorizontalValue = jspo.getHorizontalScrollBar().getValue(); - // Check scroll to Bottom - { - jspo.scrollToBottom(); - int currentValue = jspo.getVerticalScrollBar().getValue(); - System.out.println("Final Value = " + currentValue); - assertTrue("Scroll to Bottom of Pane " - + "(initialVerticalValue, actual value: " + initialVerticalValue + " " - + "< currentValue, actual value = " + currentValue + ")", - initialVerticalValue < currentValue); - } + System.out.println("Initial Vertical Value = " + jspo.getVerticalScrollBar().getValue()); + System.out.println("Initial HoriZontal Value = " + jspo.getHorizontalScrollBar().getValue()); - // Check scroll to Top - { - jspo.scrollToTop(); - int currentValue = jspo.getVerticalScrollBar().getValue(); - System.out.println("Top Scroll Final Value = " + currentValue); - assertTrue("Scroll to Top of Pane " - + "(initialVerticalValue, actual value: " + initialVerticalValue + " " - + "> currentValue, actual value = " + currentValue + ")", - initialVerticalValue > currentValue); - } + // Check scroll to Bottom + { + jspo.scrollToBottom(); + int currentValue = jspo.getVerticalScrollBar().getValue(); + System.out.println("Final Value = " + currentValue); + assertTrue("Scroll to Bottom of Pane " + + "(initialVerticalValue, actual value: " + initialVerticalValue + " " + + "< currentValue, actual value = " + currentValue + ")", + initialVerticalValue < currentValue); + } - // Check scroll to Left - { - jspo.scrollToLeft(); - int currentValue = jspo.getHorizontalScrollBar().getValue(); - System.out.println("Scroll to Left Final Value = " + currentValue); - assertTrue("Scroll to Left of Pane " - + "(initialHorizontalValue, actual value: " + initialHorizontalValue + " " - + "> currentValue, actual value = " + currentValue + ")", - initialHorizontalValue > currentValue); - } + // Check scroll to Top + { + jspo.scrollToTop(); + int currentValue = jspo.getVerticalScrollBar().getValue(); + System.out.println("Top Scroll Final Value = " + currentValue); + assertTrue("Scroll to Top of Pane " + + "(initialVerticalValue, actual value: " + initialVerticalValue + " " + + "> currentValue, actual value = " + currentValue + ")", + initialVerticalValue > currentValue); + } - // Check scroll to Right - { - jspo.scrollToRight(); - int currentValue = jspo.getHorizontalScrollBar().getValue(); - System.out.println("Scroll to Right Final Value = " + currentValue); - assertTrue("Scroll to Right of Pane " - + "(initialHorizontalValue, actual value: " + initialHorizontalValue + " " - + "< currentValue, actual value = " + currentValue + ")", - initialHorizontalValue < currentValue); - } - }); + // Check scroll to Left + { + jspo.scrollToLeft(); + int currentValue = jspo.getHorizontalScrollBar().getValue(); + System.out.println("Scroll to Left Final Value = " + currentValue); + assertTrue("Scroll to Left of Pane " + + "(initialHorizontalValue, actual value: " + initialHorizontalValue + " " + + "> currentValue, actual value = " + currentValue + ")", + initialHorizontalValue > currentValue); + } + + // Check scroll to Right + { + jspo.scrollToRight(); + int currentValue = jspo.getHorizontalScrollBar().getValue(); + System.out.println("Scroll to Right Final Value = " + currentValue); + assertTrue("Scroll to Right of Pane " + + "(initialHorizontalValue, actual value: " + initialHorizontalValue + " " + + "< currentValue, actual value = " + currentValue + ")", + initialHorizontalValue < currentValue); + } } } diff --git a/jdk/test/sanity/client/SwingSet/src/SpinnerDemoTest.java b/jdk/test/sanity/client/SwingSet/src/SpinnerDemoTest.java index 89585adb6ad..1b44efa73af 100644 --- a/jdk/test/sanity/client/SwingSet/src/SpinnerDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/SpinnerDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.spinner.SpinnerDemo; import static com.sun.swingset3.demos.spinner.SpinnerDemo.DEMO_TITLE; import java.text.DecimalFormat; @@ -30,7 +31,7 @@ import org.netbeans.jemmy.ClassReference; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JSpinnerOperator; import org.netbeans.jemmy.operators.JTextFieldOperator; -import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; +import org.testng.annotations.Listeners; /* * @test @@ -39,12 +40,13 @@ import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; * the spinner button and checking text field value. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.spinner.SpinnerDemo * @run testng SpinnerDemoTest */ +@Listeners(GuiTestListener.class) public class SpinnerDemoTest { private static final int SPINNERS_COUNT = 9; @@ -52,16 +54,14 @@ public class SpinnerDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(SpinnerDemo.class.getCanonicalName()).startApplication(); + new ClassReference(SpinnerDemo.class.getCanonicalName()).startApplication(); - JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + JFrameOperator frame = new JFrameOperator(DEMO_TITLE); - // Check changing different spinners - for (int i = 0; i < SPINNERS_COUNT; i++) { - changeValues(frame, i); - } - }); + // Check changing different spinners + for (int i = 0; i < SPINNERS_COUNT; i++) { + changeValues(frame, i); + } } private void changeValues(JFrameOperator jfo, int spinnerIndex) throws Exception { diff --git a/jdk/test/sanity/client/SwingSet/src/SplitPaneDemoTest.java b/jdk/test/sanity/client/SwingSet/src/SplitPaneDemoTest.java index 2a242cc3f16..9993d100316 100644 --- a/jdk/test/sanity/client/SwingSet/src/SplitPaneDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/SplitPaneDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.splitpane.SplitPaneDemo; import static com.sun.swingset3.demos.splitpane.SplitPaneDemo.*; import java.awt.event.KeyEvent; @@ -35,6 +36,7 @@ import org.netbeans.jemmy.operators.JRadioButtonOperator; import org.netbeans.jemmy.operators.JSplitPaneOperator; import org.netbeans.jemmy.operators.JTextFieldOperator; import static org.jemmy2ext.JemmyExt.*; +import org.testng.annotations.Listeners; /* * @test @@ -44,39 +46,39 @@ import static org.jemmy2ext.JemmyExt.*; * and changing the divider orientation. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.splitpane.SplitPaneDemo * @run testng SplitPaneDemoTest */ +@Listeners(GuiTestListener.class) public class SplitPaneDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(SplitPaneDemo.class.getCanonicalName()).startApplication(); - JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + new ClassReference(SplitPaneDemo.class.getCanonicalName()).startApplication(); - JSplitPaneOperator splitPane = new JSplitPaneOperator(frame); + JFrameOperator frame = new JFrameOperator(DEMO_TITLE); - // Toggle OneTouch Expandable - checkOneTouch(frame, splitPane, true); - checkOneTouch(frame, splitPane, false); + JSplitPaneOperator splitPane = new JSplitPaneOperator(frame); - // Check changing divider size to minimum and maximum values - changeDividerSize(frame, splitPane, 50); - changeDividerSize(frame, splitPane, 6); + // Toggle OneTouch Expandable + checkOneTouch(frame, splitPane, true); + checkOneTouch(frame, splitPane, false); - // Check moving the divider - checkDividerMoves(frame, splitPane, false); - checkDividerMoves(frame, splitPane, true); + // Check changing divider size to minimum and maximum values + changeDividerSize(frame, splitPane, 50); + changeDividerSize(frame, splitPane, 6); - // Check different minumum Day/Night sizes - changeMinimumSizes(frame, splitPane, 100); - changeMinimumSizes(frame, splitPane, 0); - }); + // Check moving the divider + checkDividerMoves(frame, splitPane, false); + checkDividerMoves(frame, splitPane, true); + + // Check different minumum Day/Night sizes + changeMinimumSizes(frame, splitPane, 100); + changeMinimumSizes(frame, splitPane, 0); } // Check for different day and night minimum size diff --git a/jdk/test/sanity/client/SwingSet/src/TabbedPaneDemoTest.java b/jdk/test/sanity/client/SwingSet/src/TabbedPaneDemoTest.java index d3d8d28245f..9b2e16b7776 100644 --- a/jdk/test/sanity/client/SwingSet/src/TabbedPaneDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/TabbedPaneDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.tabbedpane.TabbedPaneDemo; import static com.sun.swingset3.demos.tabbedpane.TabbedPaneDemo.*; import static org.jemmy2ext.JemmyExt.getLabeledContainerOperator; @@ -31,7 +32,7 @@ import org.netbeans.jemmy.operators.ContainerOperator; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JRadioButtonOperator; import org.netbeans.jemmy.operators.JTabbedPaneOperator; -import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; +import org.testng.annotations.Listeners; /* * @test @@ -40,25 +41,24 @@ import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; * positions, opening each tab and verifying the the tab gets selected. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.tabbedpane.TabbedPaneDemo * @run testng TabbedPaneDemoTest */ +@Listeners(GuiTestListener.class) public class TabbedPaneDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(TabbedPaneDemo.class.getCanonicalName()).startApplication(); + new ClassReference(TabbedPaneDemo.class.getCanonicalName()).startApplication(); - JFrameOperator mainFrame = new JFrameOperator(DEMO_TITLE); + JFrameOperator mainFrame = new JFrameOperator(DEMO_TITLE); - for (String tp : new String[]{TOP, LEFT, BOTTOM, RIGHT}) { - testTabs(mainFrame, tp); - } - }); + for (String tp : new String[]{TOP, LEFT, BOTTOM, RIGHT}) { + testTabs(mainFrame, tp); + } } public void testTabs(JFrameOperator mainFrame, String tabPlacement) throws Exception { diff --git a/jdk/test/sanity/client/SwingSet/src/TextFieldDemoTest.java b/jdk/test/sanity/client/SwingSet/src/TextFieldDemoTest.java index 4d38ce38a38..b46abaaf691 100644 --- a/jdk/test/sanity/client/SwingSet/src/TextFieldDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/TextFieldDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.textfield.JHistoryTextField; import com.sun.swingset3.demos.textfield.TextFieldDemo; import static com.sun.swingset3.demos.textfield.TextFieldDemo.*; @@ -41,6 +42,7 @@ import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JLabelOperator; import org.netbeans.jemmy.operators.JPasswordFieldOperator; import org.netbeans.jemmy.operators.JTextFieldOperator; +import org.testng.annotations.Listeners; /* * @test @@ -49,25 +51,25 @@ import org.netbeans.jemmy.operators.JTextFieldOperator; * checking that app reacts accordingly. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.textfield.TextFieldDemo * @run testng TextFieldDemoTest */ +@Listeners(GuiTestListener.class) public class TextFieldDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(TextFieldDemo.class.getCanonicalName()).startApplication(); - JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + new ClassReference(TextFieldDemo.class.getCanonicalName()).startApplication(); - historyTextField(frame); - dateTextField(frame); - passwordField(frame); - }); + JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + + historyTextField(frame); + dateTextField(frame); + passwordField(frame); } private void historyTextField(JFrameOperator jfo) throws Exception { diff --git a/jdk/test/sanity/client/SwingSet/src/ToggleButtonDemoTest.java b/jdk/test/sanity/client/SwingSet/src/ToggleButtonDemoTest.java index c240540739e..2f1b6f01a9f 100644 --- a/jdk/test/sanity/client/SwingSet/src/ToggleButtonDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/ToggleButtonDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.DemoProperties; import com.sun.swingset3.demos.togglebutton.DirectionPanel; import com.sun.swingset3.demos.togglebutton.LayoutControlPanel; @@ -40,7 +41,7 @@ import org.netbeans.jemmy.operators.JCheckBoxOperator; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JRadioButtonOperator; import org.netbeans.jemmy.operators.JTabbedPaneOperator; -import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; +import org.testng.annotations.Listeners; /* * @test @@ -53,50 +54,49 @@ import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; * selected. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.togglebutton.ToggleButtonDemo * @run testng ToggleButtonDemoTest */ +@Listeners(GuiTestListener.class) public class ToggleButtonDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(ToggleButtonDemo.class.getCanonicalName()).startApplication(); + new ClassReference(ToggleButtonDemo.class.getCanonicalName()).startApplication(); - JFrameOperator mainFrame = new JFrameOperator(ToggleButtonDemo.class.getAnnotation(DemoProperties.class).value()); - JTabbedPaneOperator tabPane = new JTabbedPaneOperator(mainFrame); + JFrameOperator mainFrame = new JFrameOperator(ToggleButtonDemo.class.getAnnotation(DemoProperties.class).value()); + JTabbedPaneOperator tabPane = new JTabbedPaneOperator(mainFrame); - // Radio Button Toggles - testRadioButtons(getBorderTitledJPanelOperator(mainFrame, TEXT_RADIO_BUTTONS), 3, null); - testRadioButtons(getBorderTitledJPanelOperator(mainFrame, IMAGE_RADIO_BUTTONS), 3, null); - testRadioButtons(getLabeledContainerOperator(mainFrame, PAD_AMOUNT), 3, (t, i) -> DEFAULT.equals(t)); + // Radio Button Toggles + testRadioButtons(getBorderTitledJPanelOperator(mainFrame, TEXT_RADIO_BUTTONS), 3, null); + testRadioButtons(getBorderTitledJPanelOperator(mainFrame, IMAGE_RADIO_BUTTONS), 3, null); + testRadioButtons(getLabeledContainerOperator(mainFrame, PAD_AMOUNT), 3, (t, i) -> DEFAULT.equals(t)); - // switch to the Check Boxes Tab - tabPane.selectPage(CHECK_BOXES); + // switch to the Check Boxes Tab + tabPane.selectPage(CHECK_BOXES); - // Check Box Toggles - ContainerOperator textCheckBoxesJPanel = getBorderTitledJPanelOperator(mainFrame, TEXT_CHECKBOXES); - testCheckBox(textCheckBoxesJPanel, CHECK1, false); - testCheckBox(textCheckBoxesJPanel, CHECK2, false); - testCheckBox(textCheckBoxesJPanel, CHECK3, false); + // Check Box Toggles + ContainerOperator textCheckBoxesJPanel = getBorderTitledJPanelOperator(mainFrame, TEXT_CHECKBOXES); + testCheckBox(textCheckBoxesJPanel, CHECK1, false); + testCheckBox(textCheckBoxesJPanel, CHECK2, false); + testCheckBox(textCheckBoxesJPanel, CHECK3, false); - ContainerOperator imageCheckBoxesJPanel = getBorderTitledJPanelOperator(mainFrame, IMAGE_CHECKBOXES); - testCheckBox(imageCheckBoxesJPanel, CHECK1, false); - testCheckBox(imageCheckBoxesJPanel, CHECK2, false); - testCheckBox(imageCheckBoxesJPanel, CHECK3, false); + ContainerOperator imageCheckBoxesJPanel = getBorderTitledJPanelOperator(mainFrame, IMAGE_CHECKBOXES); + testCheckBox(imageCheckBoxesJPanel, CHECK1, false); + testCheckBox(imageCheckBoxesJPanel, CHECK2, false); + testCheckBox(imageCheckBoxesJPanel, CHECK3, false); - ContainerOperator displayOptionsContainer = getLabeledContainerOperator(mainFrame, DISPLAY_OPTIONS); - testCheckBox(displayOptionsContainer, PAINT_BORDER, false); - testCheckBox(displayOptionsContainer, PAINT_FOCUS, true); - testCheckBox(displayOptionsContainer, ENABLED, true); - testCheckBox(displayOptionsContainer, CONTENT_FILLED, true); + ContainerOperator displayOptionsContainer = getLabeledContainerOperator(mainFrame, DISPLAY_OPTIONS); + testCheckBox(displayOptionsContainer, PAINT_BORDER, false); + testCheckBox(displayOptionsContainer, PAINT_FOCUS, true); + testCheckBox(displayOptionsContainer, ENABLED, true); + testCheckBox(displayOptionsContainer, CONTENT_FILLED, true); - // Direction Button Toggles - testToggleButtons(mainFrame); - }); + // Direction Button Toggles + testToggleButtons(mainFrame); } /** diff --git a/jdk/test/sanity/client/SwingSet/src/TreeDemoTest.java b/jdk/test/sanity/client/SwingSet/src/TreeDemoTest.java index b558d6fb96c..31166c12918 100644 --- a/jdk/test/sanity/client/SwingSet/src/TreeDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/TreeDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.tree.TreeDemo; import static com.sun.swingset3.demos.tree.TreeDemo.DEMO_TITLE; import javax.swing.tree.TreePath; @@ -29,7 +30,7 @@ import org.testng.annotations.Test; import org.netbeans.jemmy.ClassReference; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JTreeOperator; -import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; +import org.testng.annotations.Listeners; /* * @test @@ -42,67 +43,67 @@ import static org.jemmy2ext.JemmyExt.captureDebugInfoOnFail; * vertically (as ScrollPane allows it). * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.tree.TreeDemo * @run testng TreeDemoTest */ +@Listeners(GuiTestListener.class) public class TreeDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(TreeDemo.class.getCanonicalName()).startApplication(); - JFrameOperator frame = new JFrameOperator(DEMO_TITLE); + new ClassReference(TreeDemo.class.getCanonicalName()).startApplication(); - JTreeOperator tree = new JTreeOperator(frame); + JFrameOperator frame = new JFrameOperator(DEMO_TITLE); - assertEquals("Initial number of rows in the tree", 4, tree.getRowCount()); + JTreeOperator tree = new JTreeOperator(frame); - int initialTreeHeight = tree.getHeight(); + assertEquals("Initial number of rows in the tree", 4, tree.getRowCount()); - // expand all nodes - int expandsCount = 0; - for (int i = 0; i < tree.getRowCount(); i++) { - TreePath tp = tree.getPathForRow(i); - if (tree.getChildCount(tp) > 0 && !tree.isExpanded(tp)) { - tree.expandRow(i); - expandsCount++; - } + int initialTreeHeight = tree.getHeight(); + + // expand all nodes + int expandsCount = 0; + for (int i = 0; i < tree.getRowCount(); i++) { + TreePath tp = tree.getPathForRow(i); + if (tree.getChildCount(tp) > 0 && !tree.isExpanded(tp)) { + tree.expandRow(i); + expandsCount++; } + } - assertEquals("Number of rows expanded", 75, expandsCount); - assertEquals("Number of rows in the tree after expanding all of them", - 616, tree.getRowCount()); + assertEquals("Number of rows expanded", 75, expandsCount); + assertEquals("Number of rows in the tree after expanding all of them", + 616, tree.getRowCount()); - int expandedTreeHeight = tree.getHeight(); - assertTrue("Expanded tree height has increased, current " - + expandedTreeHeight + " > initial " + initialTreeHeight, - expandedTreeHeight > initialTreeHeight); + int expandedTreeHeight = tree.getHeight(); + assertTrue("Expanded tree height has increased, current " + + expandedTreeHeight + " > initial " + initialTreeHeight, + expandedTreeHeight > initialTreeHeight); - // collapse all nodes - int collapsesCount = 0; - for (int i = tree.getRowCount() - 1; i >= 0; i--) { - TreePath tp = tree.getPathForRow(i); - if (tree.getChildCount(tp) > 0 && tree.isExpanded(tp)) { - tree.collapseRow(i); - collapsesCount++; - } + // collapse all nodes + int collapsesCount = 0; + for (int i = tree.getRowCount() - 1; i >= 0; i--) { + TreePath tp = tree.getPathForRow(i); + if (tree.getChildCount(tp) > 0 && tree.isExpanded(tp)) { + tree.collapseRow(i); + collapsesCount++; } + } - assertEquals("Number of rows collapsed", 76, collapsesCount); - assertEquals("Number of rows in the tree after collapsing all of them", - 1, tree.getRowCount()); + assertEquals("Number of rows collapsed", 76, collapsesCount); + assertEquals("Number of rows in the tree after collapsing all of them", + 1, tree.getRowCount()); - int collapsedTreeHeight = tree.getHeight(); - assertTrue("Collpased tree height is not longer than initial, " - + "current " + collapsedTreeHeight + " <= initial " - + initialTreeHeight, - collapsedTreeHeight <= initialTreeHeight); + int collapsedTreeHeight = tree.getHeight(); + assertTrue("Collpased tree height is not longer than initial, " + + "current " + collapsedTreeHeight + " <= initial " + + initialTreeHeight, + collapsedTreeHeight <= initialTreeHeight); - }); } } diff --git a/jdk/test/sanity/client/SwingSet/src/WindowDemoTest.java b/jdk/test/sanity/client/SwingSet/src/WindowDemoTest.java index ef0fb850360..57b3ead00a3 100644 --- a/jdk/test/sanity/client/SwingSet/src/WindowDemoTest.java +++ b/jdk/test/sanity/client/SwingSet/src/WindowDemoTest.java @@ -21,6 +21,7 @@ * questions. */ +import org.jtregext.GuiTestListener; import com.sun.swingset3.demos.window.WindowDemo; import static com.sun.swingset3.demos.window.WindowDemo.*; import static org.jemmy2ext.JemmyExt.*; @@ -31,6 +32,7 @@ import org.netbeans.jemmy.operators.JButtonOperator; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JLabelOperator; import org.netbeans.jemmy.operators.WindowOperator; +import org.testng.annotations.Listeners; /* * @test @@ -40,37 +42,37 @@ import org.netbeans.jemmy.operators.WindowOperator; * when the "Show JWindow..." button is clicked. * * @library /sanity/client/lib/jemmy/src - * @library /sanity/client/lib/Jemmy2Ext/src + * @library /sanity/client/lib/Extensions/src * @library /sanity/client/lib/SwingSet3/src * @build org.jemmy2ext.JemmyExt * @build com.sun.swingset3.demos.window.WindowDemo * @run testng WindowDemoTest */ +@Listeners(GuiTestListener.class) public class WindowDemoTest { @Test public void test() throws Exception { - captureDebugInfoOnFail(() -> { - new ClassReference(WindowDemo.class.getCanonicalName()).startApplication(); - JFrameOperator frame = new JFrameOperator(); + new ClassReference(WindowDemo.class.getCanonicalName()).startApplication(); - assertEquals("Only one JWindow is shown", 1, getJWindowCount()); + JFrameOperator frame = new JFrameOperator(); - WindowOperator window = new WindowOperator(getJWindow()); + assertEquals("Only one JWindow is shown", 1, getJWindowCount()); - assertTrue("JFrame is showing", frame.isShowing()); - assertFalse("JFrame is not iconified", isIconified(frame)); - assertTrue("JWindow is showing", window.isShowing()); + WindowOperator window = new WindowOperator(getJWindow()); - final String labelText = I_HAVE_NO_SYSTEM_BORDER; - JLabelOperator jLabelOperator = new JLabelOperator(window, labelText); - assertEquals("JWindow contains the label with corresponding text", labelText, jLabelOperator.getText()); + assertTrue("JFrame is showing", frame.isShowing()); + assertFalse("JFrame is not iconified", isIconified(frame)); + assertTrue("JWindow is showing", window.isShowing()); - new JButtonOperator(frame, SHOW_J_WINDOW).push(); + final String labelText = I_HAVE_NO_SYSTEM_BORDER; + JLabelOperator jLabelOperator = new JLabelOperator(window, labelText); + assertEquals("JWindow contains the label with corresponding text", labelText, jLabelOperator.getText()); - assertEquals("Only one JWindow is shown", 1, getJWindowCount()); - }); + new JButtonOperator(frame, SHOW_J_WINDOW).push(); + + assertEquals("Only one JWindow is shown", 1, getJWindowCount()); } } diff --git a/jdk/test/sanity/client/lib/Jemmy2Ext/src/org/jemmy2ext/JemmyExt.java b/jdk/test/sanity/client/lib/Extensions/src/org/jemmy2ext/JemmyExt.java similarity index 97% rename from jdk/test/sanity/client/lib/Jemmy2Ext/src/org/jemmy2ext/JemmyExt.java rename to jdk/test/sanity/client/lib/Extensions/src/org/jemmy2ext/JemmyExt.java index fe0431b684e..f2d344f4c3f 100644 --- a/jdk/test/sanity/client/lib/Jemmy2Ext/src/org/jemmy2ext/JemmyExt.java +++ b/jdk/test/sanity/client/lib/Extensions/src/org/jemmy2ext/JemmyExt.java @@ -258,20 +258,19 @@ public class JemmyExt { } /** - * Wraps the test code so that in case of any failure as much information as - * possible is captured - * - * @param r test code Runnable - * @throws Exception whatever exception the test may throw + * Dispose all AWT/Swing windows causing event thread to stop */ - public static void captureDebugInfoOnFail(RunnableWithException r) throws Exception { - // TODO: Remove this once https://bugs.openjdk.java.net/browse/JDK-8151671 is fixed + public static void disposeAllWindows() { + System.out.println("disposeAllWindows"); try { - r.run(); - System.out.println("TEST PASSED"); - } catch (Throwable t) { - captureAll(); - throw t; + EventQueue.invokeAndWait(() -> { + Window[] windows = Window.getWindows(); + for (Window w : windows) { + w.dispose(); + } + }); + } catch (InterruptedException | InvocationTargetException ex) { + Logger.getLogger(JemmyExt.class.getName()).log(Level.SEVERE, "Failed to dispose all windows", ex); } } diff --git a/jdk/test/sanity/client/lib/Extensions/src/org/jtregext/GuiTestListener.java b/jdk/test/sanity/client/lib/Extensions/src/org/jtregext/GuiTestListener.java new file mode 100644 index 00000000000..407fd52d292 --- /dev/null +++ b/jdk/test/sanity/client/lib/Extensions/src/org/jtregext/GuiTestListener.java @@ -0,0 +1,72 @@ +package org.jtregext; + +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 org.jemmy2ext.JemmyExt; +import static org.jemmy2ext.JemmyExt.captureAll; +import org.testng.ITestContext; +import org.testng.ITestListener; +import org.testng.ITestResult; + +// TODO: Remove this once https://bugs.openjdk.java.net/browse/JDK-8151671 is fixed +public class GuiTestListener implements ITestListener { + + private void afterTest() { + JemmyExt.disposeAllWindows(); + } + + @Override + public void onTestStart(ITestResult result) { + } + + @Override + public void onTestSuccess(ITestResult result) { + System.out.println("TEST PASSED"); + afterTest(); + } + + @Override + public void onTestFailure(ITestResult result) { + captureAll(); + afterTest(); + } + + @Override + public void onTestSkipped(ITestResult result) { + } + + @Override + public void onTestFailedButWithinSuccessPercentage(ITestResult result) { + } + + @Override + public void onStart(ITestContext context) { + } + + @Override + public void onFinish(ITestContext context) { + } + +} diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tabbedpane/TabbedPaneDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tabbedpane/TabbedPaneDemo.java index 5d023405b58..84336d822c2 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tabbedpane/TabbedPaneDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tabbedpane/TabbedPaneDemo.java @@ -204,7 +204,9 @@ public class TabbedPaneDemo extends JPanel implements ActionListener { } public void go() { - animator = new javax.swing.Timer(22 + 22 + 22, this); + if (animator == null) { + animator = new javax.swing.Timer(22 + 22 + 22, this); + } animator.start(); } @@ -246,7 +248,7 @@ public class TabbedPaneDemo extends JPanel implements ActionListener { @Override public void actionPerformed(ActionEvent e) { - if (isVisible()) { + if (isShowing()) { repaint(); } else { animator.stop(); From 83f65483e4e23571c1fe35d64f8b0227ee05a170 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Wed, 27 Apr 2016 18:13:19 -0700 Subject: [PATCH 166/222] 8150382: JShell API: Allow setting remote JVM arguments 8151754: jshell tool: add command line options for setting feedback mode Reviewed-by: jlahoda --- .../internal/jshell/tool/ArgTokenizer.java | 8 ++- .../jdk/internal/jshell/tool/Feedback.java | 32 +++++------ .../jdk/internal/jshell/tool/JShellTool.java | 57 +++++++++++++++++-- .../jshell/tool/resources/l10n.properties | 25 +++++--- .../classes/jdk/jshell/ExecutionControl.java | 14 +++-- .../share/classes/jdk/jshell/JShell.java | 22 ++++++- .../test/jdk/jshell/StartOptionTest.java | 31 ++++++++-- langtools/test/jdk/jshell/ToolSimpleTest.java | 37 +++++++++++- 8 files changed, 185 insertions(+), 41 deletions(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java index 2e86d9de290..a7105cf1dc8 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java @@ -35,6 +35,7 @@ import java.util.stream.Stream; class ArgTokenizer { private final String str; + private final String prefix; private final int length; private int next = 0; private char buf[] = new char[20]; @@ -49,7 +50,12 @@ class ArgTokenizer { private boolean isQuoted = false; ArgTokenizer(String arg) { + this("", arg); + } + + ArgTokenizer(String prefix, String arg) { this.str = arg; + this.prefix = prefix; this.length = arg.length(); quoteChar('"'); quoteChar('\''); @@ -88,7 +94,7 @@ class ArgTokenizer { } String whole() { - return str; + return prefix + str; } void mark() { diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java index 958116c6987..21ac481bd1e 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java @@ -95,20 +95,20 @@ class Feedback { return mode.getContinuationPrompt(nextId); } - public boolean setFeedback(JShellTool tool, ArgTokenizer at) { - return new Setter(tool, at).setFeedback(); + public boolean setFeedback(MessageHandler messageHandler, ArgTokenizer at) { + return new Setter(messageHandler, at).setFeedback(); } - public boolean setFormat(JShellTool tool, ArgTokenizer at) { - return new Setter(tool, at).setFormat(); + public boolean setFormat(MessageHandler messageHandler, ArgTokenizer at) { + return new Setter(messageHandler, at).setFormat(); } - public boolean setNewMode(JShellTool tool, ArgTokenizer at) { - return new Setter(tool, at).setNewMode(); + public boolean setNewMode(MessageHandler messageHandler, ArgTokenizer at) { + return new Setter(messageHandler, at).setNewMode(); } - public boolean setPrompt(JShellTool tool, ArgTokenizer at) { - return new Setter(tool, at).setPrompt(); + public boolean setPrompt(MessageHandler messageHandler, ArgTokenizer at) { + return new Setter(messageHandler, at).setPrompt(); } { @@ -529,26 +529,26 @@ class Feedback { private class Setter { private final ArgTokenizer at; - private final JShellTool tool; + private final MessageHandler messageHandler; boolean valid = true; - Setter(JShellTool tool, ArgTokenizer at) { - this.tool = tool; + Setter(MessageHandler messageHandler, ArgTokenizer at) { + this.messageHandler = messageHandler; this.at = at; } void fluff(String format, Object... args) { - tool.fluff(format, args); + messageHandler.fluff(format, args); } - void fluffmsg(String format, Object... args) { - tool.fluffmsg(format, args); + void fluffmsg(String messageKey, Object... args) { + messageHandler.fluffmsg(messageKey, args); } void errorat(String messageKey, Object... args) { Object[] a2 = Arrays.copyOf(args, args.length + 2); - a2[args.length] = "/set " + at.whole(); - tool.errormsg(messageKey, a2); + a2[args.length] = at.whole(); + messageHandler.errormsg(messageKey, a2); } // For /set prompt "" "" diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index 144de11c114..b6cd1a370f6 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -108,7 +108,7 @@ import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND; * Command line REPL tool for Java using the JShell API. * @author Robert Field */ -public class JShellTool { +public class JShellTool implements MessageHandler { private static final String LINE_SEP = System.getProperty("line.separator"); private static final Pattern LINEBREAK = Pattern.compile("\\R"); @@ -166,6 +166,8 @@ public class JShellTool { private boolean regenerateOnDeath = true; private boolean live = false; private boolean feedbackInitialized = false; + private String initialMode = null; + private List remoteVMOptions = new ArrayList<>(); SourceCodeAnalysis analysis; JShell state = null; @@ -256,7 +258,8 @@ public class JShellTool { * @param format printf format * @param args printf args */ - void fluff(String format, Object... args) { + @Override + public void fluff(String format, Object... args) { if (feedback.shouldDisplayCommandFluff() && interactive()) { hard(format, args); } @@ -362,7 +365,8 @@ public class JShellTool { * @param key the resource key * @param args */ - void errormsg(String key, Object... args) { + @Override + public void errormsg(String key, Object... args) { cmdout.println(prefix(messageFormat(key, args), feedback.getErrorPre())); } @@ -383,7 +387,8 @@ public class JShellTool { * @param key the resource key * @param args */ - void fluffmsg(String key, Object... args) { + @Override + public void fluffmsg(String key, Object... args) { if (feedback.shouldDisplayCommandFluff() && interactive()) { hardmsg(key, args); } @@ -512,6 +517,23 @@ public class JShellTool { case "-fullversion": cmdout.printf("jshell %s\n", fullVersion()); return null; + case "-feedback": + if (ai.hasNext()) { + initialMode = ai.next(); + } else { + startmsg("jshell.err.opt.feedback.arg"); + return null; + } + break; + case "-q": + initialMode = "concise"; + break; + case "-qq": + initialMode = "silent"; + break; + case "-v": + initialMode = "verbose"; + break; case "-startup": if (cmdlineStartup != null) { startmsg("jshell.err.opt.startup.conflict"); @@ -530,6 +552,10 @@ public class JShellTool { cmdlineStartup = ""; break; default: + if (arg.startsWith("-R")) { + remoteVMOptions.add(arg.substring(2)); + break; + } startmsg("jshell.err.opt.unknown", arg); printUsage(); return null; @@ -567,6 +593,7 @@ public class JShellTool { .idGenerator((sn, i) -> (currentNameSpace == startNamespace || state.status(sn).isActive) ? currentNameSpace.tid(sn) : errorNamespace.tid(sn)) + .remoteVMOptions(remoteVMOptions.toArray(new String[remoteVMOptions.size()])) .build(); shutdownSubscription = state.onShutdown((JShell deadState) -> { if (deadState == state) { @@ -596,6 +623,26 @@ public class JShellTool { start = cmdlineStartup; } startUpRun(start); + if (initialMode != null) { + MessageHandler mh = new MessageHandler() { + @Override + public void fluff(String format, Object... args) { + } + + @Override + public void fluffmsg(String messageKey, Object... args) { + } + + @Override + public void errormsg(String messageKey, Object... args) { + startmsg(messageKey, args); + } + }; + if (!feedback.setFeedback(mh, new ArgTokenizer("-feedback ", initialMode))) { + regenerateOnDeath = false; + } + initialMode = null; + } currentNameSpace = mainNamespace; } //where @@ -1050,7 +1097,7 @@ public class JShellTool { "format", "feedback", "newmode", "prompt", "editor", "start"}; final boolean cmdSet(String arg) { - ArgTokenizer at = new ArgTokenizer(arg.trim()); + ArgTokenizer at = new ArgTokenizer("/set ", arg.trim()); String which = setSubCommand(at); if (which == null) { return false; diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties index b70c6de2ac0..06784c86582 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties @@ -28,6 +28,7 @@ Welcome to JShell -- Version {0}\n\ For an introduction type: /help intro\n jshell.err.opt.classpath.conflict = Conflicting -classpath option. jshell.err.opt.classpath.arg = Argument to -classpath missing. +jshell.err.opt.feedback.arg = Argument to -feedback missing. Mode required. jshell.err.opt.startup.conflict = Conflicting -startup or -nostartup option. jshell.err.opt.unknown = Unknown option: {0} @@ -128,13 +129,23 @@ jshell.console.incomplete = \nResults may be incomplete; try again later for com help.usage = \ Usage: jshell \n\ -where possible options include:\n\t\ - -classpath Specify where to find user class files\n\t\ - -cp Specify where to find user class files\n\t\ - -startup One run replacement for the start-up definitions\n\t\ - -nostartup Do not run the start-up definitions\n\t\ - -help Print a synopsis of standard options\n\t\ - -version Version information\n +where possible options include:\n\ +\ -classpath Specify where to find user class files\n\ +\ -cp Specify where to find user class files\n\ +\ -startup One run replacement for the start-up definitions\n\ +\ -nostartup Do not run the start-up definitions\n\ +\ -feedback Specify the initial feedback mode. The mode may be\n\ +\ predefined (silent, concise, normal, or verbose) or\n\ +\ previously user-defined\n\ +\ -q Quiet feedback. Same as: -feedback concise\n\ +\ -qq Really quiet feedback. Same as: -feedback silent\n\ +\ -v Verbose feedback. Same as: -feedback verbose\n\ +\ -J Pass directly to the runtime system.\n\ +\ Use one -J for each runtime flag or flag argument\n\ +\ -R Pass to the remote runtime system.\n\ +\ Use one -R for each remote flag or flag argument\n\ +\ -help Print this synopsis of standard options\n\ +\ -version Version information\n help.list.summary = list the source you have typed help.list.args = [all|start|] diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java index f69ec57e797..40186742741 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java @@ -57,11 +57,19 @@ class ExecutionControl { private ObjectInputStream in; private ObjectOutputStream out; private final JShell proc; + private final String remoteVMOptions; - ExecutionControl(JDIEnv env, SnippetMaps maps, JShell proc) { + ExecutionControl(JDIEnv env, SnippetMaps maps, JShell proc, List extraRemoteVMOptions) { this.env = env; this.maps = maps; this.proc = proc; + StringBuilder sb = new StringBuilder(); + extraRemoteVMOptions.stream() + .forEach(s -> { + sb.append(" "); + sb.append(s); + }); + this.remoteVMOptions = sb.toString(); } void launch() throws IOException { @@ -257,11 +265,9 @@ class ExecutionControl { // Locale.getDefault()); String connectorName = "com.sun.jdi.CommandLineLaunch"; - String classPath = System.getProperty("java.class.path"); - String javaArgs = "-classpath " + classPath; Map argumentName2Value = new HashMap<>(); argumentName2Value.put("main", "jdk.internal.jshell.remote.RemoteAgent " + port); - argumentName2Value.put("options", javaArgs); + argumentName2Value.put("options", remoteVMOptions); boolean launchImmediately = true; int traceFlags = 0;// VirtualMachine.TRACE_SENDS | VirtualMachine.TRACE_EVENTS; diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java index 0cb2d05c7af..8b95bbdc7ff 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java @@ -26,10 +26,11 @@ package jdk.jshell; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -84,6 +85,7 @@ public class JShell implements AutoCloseable { final PrintStream err; final Supplier tempVariableNameGenerator; final BiFunction idGenerator; + final List extraRemoteVMOptions; private int nextKeyIndex = 1; @@ -105,6 +107,7 @@ public class JShell implements AutoCloseable { this.err = b.err; this.tempVariableNameGenerator = b.tempVariableNameGenerator; this.idGenerator = b.idGenerator; + this.extraRemoteVMOptions = b.extraRemoteVMOptions; this.maps = new SnippetMaps(this); this.keyMap = new KeyMap(this); @@ -139,6 +142,7 @@ public class JShell implements AutoCloseable { PrintStream err = System.err; Supplier tempVariableNameGenerator = null; BiFunction idGenerator = null; + List extraRemoteVMOptions = new ArrayList<>(); Builder() { } @@ -263,6 +267,18 @@ public class JShell implements AutoCloseable { return this; } + /** + * Set additional VM options for launching the VM. + * + * @param options The options for the remote VM. + * @return the Builder instance (for use in chained + * initialization). + */ + public Builder remoteVMOptions(String... options) { + this.extraRemoteVMOptions.addAll(Arrays.asList(options)); + return this; + } + /** * Build a JShell state engine. This is the entry-point to all JShell * functionality. This creates a remote process for execution. It is @@ -621,10 +637,10 @@ public class JShell implements AutoCloseable { ExecutionControl executionControl() { if (executionControl == null) { - this.executionControl = new ExecutionControl(new JDIEnv(this), maps, this); + this.executionControl = new ExecutionControl(new JDIEnv(this), maps, this, extraRemoteVMOptions); try { executionControl.launch(); - } catch (IOException ex) { + } catch (Throwable ex) { throw new InternalError("Launching JDI execution engine threw: " + ex.getMessage(), ex); } } diff --git a/langtools/test/jdk/jshell/StartOptionTest.java b/langtools/test/jdk/jshell/StartOptionTest.java index b813b35691c..071b1523b9d 100644 --- a/langtools/test/jdk/jshell/StartOptionTest.java +++ b/langtools/test/jdk/jshell/StartOptionTest.java @@ -22,7 +22,7 @@ */ /* - * @test + * @test 8151754 * @summary Testing start-up options. * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -34,6 +34,7 @@ */ import java.io.ByteArrayOutputStream; +import java.io.OutputStream; import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.nio.file.Path; @@ -47,6 +48,7 @@ import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; @Test public class StartOptionTest { @@ -55,9 +57,24 @@ public class StartOptionTest { private ByteArrayOutputStream err; private JShellTool getShellTool() { - return new JShellTool(null, new PrintStream(out), new PrintStream(err), null, null, null, - null, new ReplToolTesting.MemoryPreferences(), - Locale.ROOT); + class NoOutputAllowedStream extends OutputStream { + private final String label; + NoOutputAllowedStream(String label) { + this.label = label; + } + @Override + public void write(int b) { fail("Unexpected output to: " + label); } + } + return new JShellTool( + new TestingInputStream(), + new PrintStream(out), + new PrintStream(err), + new PrintStream(new NoOutputAllowedStream("console")), + new TestingInputStream(), + new PrintStream(new NoOutputAllowedStream("userout")), + new PrintStream(new NoOutputAllowedStream("usererr")), + new ReplToolTesting.MemoryPreferences(), + Locale.ROOT); } private String getOutput() { @@ -132,6 +149,12 @@ public class StartOptionTest { } } + @Test + public void testNegFeedbackOption() throws Exception { + start("", "Argument to -feedback missing. Mode required.", "-feedback"); + start("", "Does not match any current feedback mode: blorp -- -feedback blorp", "-feedback", "blorp"); + } + @Test public void testVersion() throws Exception { start(s -> assertTrue(s.startsWith("jshell")), null, "-version"); diff --git a/langtools/test/jdk/jshell/ToolSimpleTest.java b/langtools/test/jdk/jshell/ToolSimpleTest.java index 069e571fa41..b0c97a77f0b 100644 --- a/langtools/test/jdk/jshell/ToolSimpleTest.java +++ b/langtools/test/jdk/jshell/ToolSimpleTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8153716 8143955 + * @bug 8153716 8143955 8151754 8150382 * @summary Simple jshell tool tests * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -349,4 +349,39 @@ public class ToolSimpleTest extends ReplToolTesting { System.setProperty("java.awt.headless", prevHeadless==null? "false" : prevHeadless); } } + + public void testOptionQ() { + test(new String[]{"-q", "-nostartup"}, + (a) -> assertCommand(a, "1+1", "$1 ==> 2"), + (a) -> assertCommand(a, "int x = 5", "") + ); + } + + public void testOptionQq() { + test(new String[]{"-qq", "-nostartup"}, + (a) -> assertCommand(a, "1+1", "") + ); + } + + public void testOptionV() { + test(new String[]{"-v", "-nostartup"}, + (a) -> assertCommand(a, "1+1", + "$1 ==> 2\n" + + "| created scratch variable $1 : int") + ); + } + + public void testOptionFeedback() { + test(new String[]{"-feedback", "concise", "-nostartup"}, + (a) -> assertCommand(a, "1+1", "$1 ==> 2"), + (a) -> assertCommand(a, "int x = 5", "") + ); + } + + public void testOptionR() { + test(new String[]{"-R-Dthe.sound=blorp", "-nostartup"}, + (a) -> assertCommand(a, "System.getProperty(\"the.sound\")", + "$1 ==> \"blorp\"") + ); + } } From 7e90d3bb14ae2ded0897132f7a57feea5cc387a7 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Wed, 27 Apr 2016 19:56:44 -0700 Subject: [PATCH 167/222] 8155580: jshell tool: push for -R missed added file MessageHandler.java Reviewed-by: jlahoda --- .../internal/jshell/tool/MessageHandler.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/MessageHandler.java diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/MessageHandler.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/MessageHandler.java new file mode 100644 index 00000000000..4014f4b423e --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/MessageHandler.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.internal.jshell.tool; + + +/** + * User message reporting support + * + * @author Robert Field + */ +public interface MessageHandler { + + void fluff(String format, Object... args); + + void fluffmsg(String messageKey, Object... args); + + void errormsg(String messageKey, Object... args); +} From 560adadb050cf54561f212ab0bd46d8a975112c8 Mon Sep 17 00:00:00 2001 From: Felix Yang Date: Thu, 28 Apr 2016 12:38:22 +0800 Subject: [PATCH 168/222] 8154733: Fix module dependencies missed in java.rmi tests Reviewed-by: alanb, amlu --- jdk/test/java/rmi/TEST.properties | 1 + jdk/test/java/rmi/reliability/benchmark/bench/serial/Main.java | 3 ++- jdk/test/sun/rmi/TEST.properties | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/rmi/TEST.properties create mode 100644 jdk/test/sun/rmi/TEST.properties diff --git a/jdk/test/java/rmi/TEST.properties b/jdk/test/java/rmi/TEST.properties new file mode 100644 index 00000000000..d4bbfc905b9 --- /dev/null +++ b/jdk/test/java/rmi/TEST.properties @@ -0,0 +1 @@ +modules = java.rmi diff --git a/jdk/test/java/rmi/reliability/benchmark/bench/serial/Main.java b/jdk/test/java/rmi/reliability/benchmark/bench/serial/Main.java index 8f9b715867f..5e6358dba7f 100644 --- a/jdk/test/java/rmi/reliability/benchmark/bench/serial/Main.java +++ b/jdk/test/java/rmi/reliability/benchmark/bench/serial/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,7 @@ * @summary The Serialization benchmark test. This java class is used to run the * test under JTREG. * @library ../../ + * @modules java.desktop * @build bench.BenchInfo bench.HtmlReporter bench.Util bench.Benchmark * @build bench.Reporter bench.XmlReporter bench.ConfigFormatException * @build bench.Harness bench.TextReporter diff --git a/jdk/test/sun/rmi/TEST.properties b/jdk/test/sun/rmi/TEST.properties new file mode 100644 index 00000000000..d4bbfc905b9 --- /dev/null +++ b/jdk/test/sun/rmi/TEST.properties @@ -0,0 +1 @@ +modules = java.rmi From 1ac868ea613abe892aa2144a3f202871d74ceb06 Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Thu, 28 Apr 2016 05:10:11 +0000 Subject: [PATCH 169/222] 8154119: Module summary page should display module description Reviewed-by: jjg --- .../formats/html/ModuleWriterImpl.java | 15 ++ .../doclets/formats/html/SectionName.java | 3 +- .../formats/html/markup/HtmlConstants.java | 8 +- .../doclets/toolkit/ModuleSummaryWriter.java | 8 + .../builders/ModuleSummaryBuilder.java | 13 ++ .../doclets/toolkit/resources/doclet.xml | 1 + .../doclet/testModules/TestModules.java | 145 ++++++++++++++++++ .../testModules/module1/module-info.java | 33 ++++ .../testpkgmdl1/TestClassInModule1.java | 28 ++++ .../testModules/module2/module-info.java | 31 ++++ .../testpkgmdl2/TestClassInModule2.java | 28 ++++ 11 files changed, 311 insertions(+), 2 deletions(-) create mode 100644 langtools/test/jdk/javadoc/doclet/testModules/TestModules.java create mode 100644 langtools/test/jdk/javadoc/doclet/testModules/module1/module-info.java create mode 100644 langtools/test/jdk/javadoc/doclet/testModules/module1/testpkgmdl1/TestClassInModule1.java create mode 100644 langtools/test/jdk/javadoc/doclet/testModules/module2/module-info.java create mode 100644 langtools/test/jdk/javadoc/doclet/testModules/module2/testpkgmdl2/TestClassInModule2.java diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java index 105cb706eeb..555f0dcb03d 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java @@ -167,6 +167,21 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW summaryContentTree.addContent(table); } + /** + * {@inheritDoc} + */ + public void addModuleDescription(Content moduleContentTree) { + if (!utils.getBody(mdle).isEmpty()) { + Content tree = configuration.allowTag(HtmlTag.SECTION) ? HtmlTree.SECTION() : moduleContentTree; + tree.addContent(HtmlConstants.START_OF_MODULE_DESCRIPTION); + tree.addContent(getMarkerAnchor(SectionName.MODULE_DESCRIPTION)); + addInlineComment(mdle, tree); + if (configuration.allowTag(HtmlTag.SECTION)) { + moduleContentTree.addContent(tree); + } + } + } + /** * Adds list of packages in the package summary table. Generate link to each package. * diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SectionName.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SectionName.java index a9ff3e50311..19e9a556c4c 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SectionName.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SectionName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,7 @@ public enum SectionName { METHOD_DETAIL("method.detail"), METHODS_INHERITANCE("methods.inherited.from.class."), METHOD_SUMMARY("method.summary"), + MODULE_DESCRIPTION("module.description"), NAVBAR_BOTTOM("navbar.bottom"), NAVBAR_BOTTOM_FIRSTROW("navbar.bottom.firstrow"), NAVBAR_TOP("navbar.top"), diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlConstants.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlConstants.java index 1b7731badf2..8807cd75bba 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlConstants.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,12 @@ public class HtmlConstants { public static final Content END_OF_BOTTOM_NAVBAR = new Comment("======== END OF BOTTOM NAVBAR ======="); + /** + * Marker to identify start of module description. + */ + public static final Content START_OF_MODULE_DESCRIPTION = + new Comment("============ MODULE DESCRIPTION ==========="); + /** * Marker to identify start of class data. */ diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ModuleSummaryWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ModuleSummaryWriter.java index 50a87a63d44..33a76b76028 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ModuleSummaryWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ModuleSummaryWriter.java @@ -73,6 +73,14 @@ public interface ModuleSummaryWriter { */ public abstract Content getSummaryTree(Content summaryContentTree); + /** + * Adds the module description. + * + * @param moduleContentTree the content tree to which the module description + * will be added + */ + public abstract void addModuleDescription(Content moduleContentTree); + /** * Adds the table of packages to the documentation tree. * diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java index d2de20daf01..a32a7f595a7 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java @@ -185,4 +185,17 @@ public class ModuleSummaryBuilder extends AbstractBuilder { packageTableSummary, summaryContentTree); } } + + /** + * Build the description for the module. + * + * @param node the XML element that specifies which components to document + * @param moduleContentTree the tree to which the module description will + * be added + */ + public void buildModuleDescription(XMLNode node, Content moduleContentTree) { + if (!configuration.nocomment) { + moduleWriter.addModuleDescription(moduleContentTree); + } + } } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclet.xml b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclet.xml index 62a3183808c..f8349031319 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclet.xml +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclet.xml @@ -30,6 +30,7 @@ +

    diff --git a/langtools/test/jdk/javadoc/doclet/testModules/TestModules.java b/langtools/test/jdk/javadoc/doclet/testModules/TestModules.java new file mode 100644 index 00000000000..d887c0933a7 --- /dev/null +++ b/langtools/test/jdk/javadoc/doclet/testModules/TestModules.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8154119 + * @summary Test modules support in javadoc. + * @author bpatel + * @library ../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build JavadocTester + * @run main TestModules + */ + +public class TestModules extends JavadocTester { + + public static void main(String... args) throws Exception { + TestModules tester = new TestModules(); + tester.runTests(); + } + + @Test + void test1() { + javadoc("-d", "out", + "-modulesourcepath", testSrc, + "-addmods", "module1,module2", + "testpkgmdl1", "testpkgmdl2"); + checkExit(Exit.OK); + testDescription(true); + testNoDescription(false); + } + + @Test + void test2() { + javadoc("-d", "out-html5", "-html5", + "-modulesourcepath", testSrc, + "-addmods", "module1,module2", + "testpkgmdl1", "testpkgmdl2"); + checkExit(Exit.OK); + testHtml5Description(true); + testHtml5NoDescription(false); + } + + @Test + void test3() { + javadoc("-d", "out-nocomment", "-nocomment", + "-modulesourcepath", testSrc, + "-addmods", "module1,module2", + "testpkgmdl1", "testpkgmdl2"); + checkExit(Exit.OK); + testDescription(false); + testNoDescription(true); + } + + @Test + void test4() { + javadoc("-d", "out-html5-nocomment", "-nocomment", "-html5", + "-modulesourcepath", testSrc, + "-addmods", "module1,module2", + "testpkgmdl1", "testpkgmdl2"); + checkExit(Exit.OK); + testHtml5Description(false); + testHtml5NoDescription(true); + } + + void testDescription(boolean found) { + checkOutput("module1-summary.html", found, + "\n" + + "\n" + + "\n" + + "\n" + + "
    This is a test description for the module1 module.
    "); + checkOutput("module2-summary.html", found, + "\n" + + "\n" + + "\n" + + "\n" + + "
    This is a test description for the module2 module.
    "); + } + + void testNoDescription(boolean found) { + checkOutput("module1-summary.html", found, + "
    \n" + + "
      \n" + + "
    • \n" + + ""); + checkOutput("module2-summary.html", found, + "
      \n" + + "
        \n" + + "
      • \n" + + "
      "); + } + + void testHtml5Description(boolean found) { + checkOutput("module1-summary.html", found, + "
      \n" + + "\n" + + "\n" + + "\n" + + "\n" + + "
      This is a test description for the module1 module.
      \n" + + "
      "); + checkOutput("module2-summary.html", found, + "
      \n" + + "\n" + + "\n" + + "\n" + + "\n" + + "
      This is a test description for the module2 module.
      \n" + + "
      "); + } + + void testHtml5NoDescription(boolean found) { + checkOutput("module1-summary.html", found, + "
      \n" + + "
        \n" + + "
      • \n" + + "
      "); + checkOutput("module2-summary.html", found, + "
      \n" + + "
        \n" + + "
      • \n" + + "
      "); + } +} diff --git a/langtools/test/jdk/javadoc/doclet/testModules/module1/module-info.java b/langtools/test/jdk/javadoc/doclet/testModules/module1/module-info.java new file mode 100644 index 00000000000..37ff3f7c77c --- /dev/null +++ b/langtools/test/jdk/javadoc/doclet/testModules/module1/module-info.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + * This is a test description for the module1 module. + */ +module module1 { + requires module2; + + exports testpkgmdl1; +} diff --git a/langtools/test/jdk/javadoc/doclet/testModules/module1/testpkgmdl1/TestClassInModule1.java b/langtools/test/jdk/javadoc/doclet/testModules/module1/testpkgmdl1/TestClassInModule1.java new file mode 100644 index 00000000000..63542730c0a --- /dev/null +++ b/langtools/test/jdk/javadoc/doclet/testModules/module1/testpkgmdl1/TestClassInModule1.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 testpkgmdl1; + +public class TestClassInModule1 { +} diff --git a/langtools/test/jdk/javadoc/doclet/testModules/module2/module-info.java b/langtools/test/jdk/javadoc/doclet/testModules/module2/module-info.java new file mode 100644 index 00000000000..13c77f05998 --- /dev/null +++ b/langtools/test/jdk/javadoc/doclet/testModules/module2/module-info.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + * This is a test description for the module2 module. + */ +module module2 { + exports testpkgmdl2; +} diff --git a/langtools/test/jdk/javadoc/doclet/testModules/module2/testpkgmdl2/TestClassInModule2.java b/langtools/test/jdk/javadoc/doclet/testModules/module2/testpkgmdl2/TestClassInModule2.java new file mode 100644 index 00000000000..d4995649b5c --- /dev/null +++ b/langtools/test/jdk/javadoc/doclet/testModules/module2/testpkgmdl2/TestClassInModule2.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 testpkgmdl2; + +public class TestClassInModule2 { +} From 1f74d8cba8fc3961285b61074b562b3a04dc1bd4 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Thu, 28 Apr 2016 09:33:18 +0100 Subject: [PATCH 170/222] 8155578: OpenJDK build failed after JDK-8044773 Reviewed-by: alanb --- jdk/src/java.base/share/classes/module-info.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java index 12ad93f6a6d..a597253d168 100644 --- a/jdk/src/java.base/share/classes/module-info.java +++ b/jdk/src/java.base/share/classes/module-info.java @@ -166,6 +166,7 @@ module java.base { java.sql, java.xml, jdk.charsets, + jdk.net, jdk.scripting.nashorn, jdk.unsupported, jdk.vm.ci; From 0f84fadba6462bf1cca60885f102d7609af90768 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 28 Apr 2016 10:42:33 +0200 Subject: [PATCH 171/222] 8155025: 0.001.toFixed(2) should return "0.00" not "0" Reviewed-by: jlaskey, hannesw --- .../runtime/doubleconv/DtoaBuffer.java | 2 + nashorn/test/script/basic/JDK-8155025.js | 37 +++++++++ .../test/script/basic/JDK-8155025.js.EXPECTED | 75 +++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 nashorn/test/script/basic/JDK-8155025.js create mode 100644 nashorn/test/script/basic/JDK-8155025.js.EXPECTED diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaBuffer.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaBuffer.java index 172118ca685..98f39c3a4e0 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaBuffer.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaBuffer.java @@ -176,6 +176,8 @@ public class DtoaBuffer { buffer.append('0'); } buffer.append(chars, 0, length); + } else { + decimalPoint = 1; } } else if (decimalPoint >= length) { // large integer, add trailing zeroes diff --git a/nashorn/test/script/basic/JDK-8155025.js b/nashorn/test/script/basic/JDK-8155025.js new file mode 100644 index 00000000000..7b1001539f8 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8155025.js @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + * JDK-8155025: 0.001.toFixed(2) should return "0.00" not "0" + * + * @test + * @run + */ + +for (var i = 0, zeros=""; i <= 9; i++, zeros += "0") { + var n = Number("0." + zeros + "1"); + for (var j = 1; j <= i + 3; j++) { + print(n + ".toFixed(" + j + ")=" + n.toFixed(j)); + } +} + diff --git a/nashorn/test/script/basic/JDK-8155025.js.EXPECTED b/nashorn/test/script/basic/JDK-8155025.js.EXPECTED new file mode 100644 index 00000000000..7cdca19c090 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8155025.js.EXPECTED @@ -0,0 +1,75 @@ +0.1.toFixed(1)=0.1 +0.1.toFixed(2)=0.10 +0.1.toFixed(3)=0.100 +0.01.toFixed(1)=0.0 +0.01.toFixed(2)=0.01 +0.01.toFixed(3)=0.010 +0.01.toFixed(4)=0.0100 +0.001.toFixed(1)=0.0 +0.001.toFixed(2)=0.00 +0.001.toFixed(3)=0.001 +0.001.toFixed(4)=0.0010 +0.001.toFixed(5)=0.00100 +0.0001.toFixed(1)=0.0 +0.0001.toFixed(2)=0.00 +0.0001.toFixed(3)=0.000 +0.0001.toFixed(4)=0.0001 +0.0001.toFixed(5)=0.00010 +0.0001.toFixed(6)=0.000100 +0.00001.toFixed(1)=0.0 +0.00001.toFixed(2)=0.00 +0.00001.toFixed(3)=0.000 +0.00001.toFixed(4)=0.0000 +0.00001.toFixed(5)=0.00001 +0.00001.toFixed(6)=0.000010 +0.00001.toFixed(7)=0.0000100 +0.000001.toFixed(1)=0.0 +0.000001.toFixed(2)=0.00 +0.000001.toFixed(3)=0.000 +0.000001.toFixed(4)=0.0000 +0.000001.toFixed(5)=0.00000 +0.000001.toFixed(6)=0.000001 +0.000001.toFixed(7)=0.0000010 +0.000001.toFixed(8)=0.00000100 +1e-7.toFixed(1)=0.0 +1e-7.toFixed(2)=0.00 +1e-7.toFixed(3)=0.000 +1e-7.toFixed(4)=0.0000 +1e-7.toFixed(5)=0.00000 +1e-7.toFixed(6)=0.000000 +1e-7.toFixed(7)=0.0000001 +1e-7.toFixed(8)=0.00000010 +1e-7.toFixed(9)=0.000000100 +1e-8.toFixed(1)=0.0 +1e-8.toFixed(2)=0.00 +1e-8.toFixed(3)=0.000 +1e-8.toFixed(4)=0.0000 +1e-8.toFixed(5)=0.00000 +1e-8.toFixed(6)=0.000000 +1e-8.toFixed(7)=0.0000000 +1e-8.toFixed(8)=0.00000001 +1e-8.toFixed(9)=0.000000010 +1e-8.toFixed(10)=0.0000000100 +1e-9.toFixed(1)=0.0 +1e-9.toFixed(2)=0.00 +1e-9.toFixed(3)=0.000 +1e-9.toFixed(4)=0.0000 +1e-9.toFixed(5)=0.00000 +1e-9.toFixed(6)=0.000000 +1e-9.toFixed(7)=0.0000000 +1e-9.toFixed(8)=0.00000000 +1e-9.toFixed(9)=0.000000001 +1e-9.toFixed(10)=0.0000000010 +1e-9.toFixed(11)=0.00000000100 +1e-10.toFixed(1)=0.0 +1e-10.toFixed(2)=0.00 +1e-10.toFixed(3)=0.000 +1e-10.toFixed(4)=0.0000 +1e-10.toFixed(5)=0.00000 +1e-10.toFixed(6)=0.000000 +1e-10.toFixed(7)=0.0000000 +1e-10.toFixed(8)=0.00000000 +1e-10.toFixed(9)=0.000000000 +1e-10.toFixed(10)=0.0000000001 +1e-10.toFixed(11)=0.00000000010 +1e-10.toFixed(12)=0.000000000100 From 9c04e65bdacd138766daeba56bdb74a1c8cb1a54 Mon Sep 17 00:00:00 2001 From: Pavel Punegov Date: Thu, 28 Apr 2016 17:58:18 +0300 Subject: [PATCH 172/222] 8155034: [TESTBUG] ctw tests fail to compile: module reads package sun.reflect from both jdk.unsupported and java.base Replace sun.reflect with jdk.internal.reflect Reviewed-by: iignatyev, ddmitriev --- .../testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java | 4 ++-- hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java | 2 +- hotspot/test/testlibrary_tests/ctw/ClassesListTest.java | 2 +- hotspot/test/testlibrary_tests/ctw/JarDirTest.java | 2 +- hotspot/test/testlibrary_tests/ctw/JarsTest.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java index f05a02a61b8..96b627a3e4e 100644 --- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java +++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ package sun.hotspot.tools.ctw; import sun.hotspot.WhiteBox; import jdk.internal.misc.SharedSecrets; -import sun.reflect.ConstantPool; +import jdk.internal.reflect.ConstantPool; import java.lang.reflect.Executable; diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java index f507fb068c5..a11436606b2 100644 --- a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java +++ b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java @@ -26,7 +26,7 @@ * @bug 8012447 * @library /testlibrary /test/lib /testlibrary/ctw/src * @modules java.base/jdk.internal.misc - * java.base/sun.reflect + * java.base/jdk.internal.reflect * java.management * @build ClassFileInstaller sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java index 5a792a0c413..f9feeaadc2c 100644 --- a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java +++ b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java @@ -26,7 +26,7 @@ * @bug 8012447 * @library /testlibrary /test/lib /testlibrary/ctw/src * @modules java.base/jdk.internal.misc - * java.base/sun.reflect + * java.base/jdk.internal.reflect * java.management * @build ClassFileInstaller sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar diff --git a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java index 1bfdc45db93..7bc97e6966c 100644 --- a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java +++ b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java @@ -26,7 +26,7 @@ * @bug 8012447 * @library /testlibrary /test/lib /testlibrary/ctw/src * @modules java.base/jdk.internal.misc - * java.base/sun.reflect + * java.base/jdk.internal.reflect * java.compiler * java.management * jdk.jvmstat/sun.jvmstat.monitor diff --git a/hotspot/test/testlibrary_tests/ctw/JarsTest.java b/hotspot/test/testlibrary_tests/ctw/JarsTest.java index 1050e512583..e35791201b8 100644 --- a/hotspot/test/testlibrary_tests/ctw/JarsTest.java +++ b/hotspot/test/testlibrary_tests/ctw/JarsTest.java @@ -26,7 +26,7 @@ * @bug 8012447 * @library /testlibrary /test/lib /testlibrary/ctw/src * @modules java.base/jdk.internal.misc - * java.base/sun.reflect + * java.base/jdk.internal.reflect * java.compiler * java.management * jdk.jvmstat/sun.jvmstat.monitor From d423c99efc29f678d79c7a8154a9f9202224f2de Mon Sep 17 00:00:00 2001 From: Kirill Zhaldybin Date: Thu, 28 Apr 2016 16:55:04 +0300 Subject: [PATCH 173/222] 8155527: New test TestHumongousClassLoader fails with "-XX:+ExplicitGCInvokesConcurrent" option Reviewed-by: dfazunen, drwhite, jwilhelm --- .../test/gc/g1/humongousObjects/TestHumongousClassLoader.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/test/gc/g1/humongousObjects/TestHumongousClassLoader.java b/hotspot/test/gc/g1/humongousObjects/TestHumongousClassLoader.java index 4e8efd6e1d9..b4bb37cacba 100644 --- a/hotspot/test/gc/g1/humongousObjects/TestHumongousClassLoader.java +++ b/hotspot/test/gc/g1/humongousObjects/TestHumongousClassLoader.java @@ -40,6 +40,7 @@ import java.nio.file.Paths; * @summary Checks that unreachable classes and unreachable humongous class loader are unloaded after GC * @requires vm.gc=="G1" | vm.gc=="null" * @requires vm.opt.G1HeapRegionSize == "null" | vm.opt.G1HeapRegionSize == "1M" + * @requires vm.opt.ExplicitGCInvokesConcurrent != true * @library /testlibrary /test/lib / * @modules java.management * @build sun.hotspot.WhiteBox From a12239e493d7dcbe1baaa3a7997a74f9c460ca49 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 28 Apr 2016 16:18:59 +0200 Subject: [PATCH 174/222] 8155641: Correct merge typo in compare script Reviewed-by: chegar --- common/autoconf/compare.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/autoconf/compare.sh.in b/common/autoconf/compare.sh.in index a6cc8d65abc..67a69ff73bd 100644 --- a/common/autoconf/compare.sh.in +++ b/common/autoconf/compare.sh.in @@ -31,7 +31,7 @@ export LEGACY_BUILD_DIR=@OPENJDK_TARGET_OS@-@OPENJDK_TARGET_CPU_LEGACY@ -sexport OPENJDK_TARGET_OS="@OPENJDK_TARGET_OS@" +export OPENJDK_TARGET_OS="@OPENJDK_TARGET_OS@" export OPENJDK_TARGET_CPU="@OPENJDK_TARGET_CPU@" export OPENJDK_TARGET_CPU_LIBDIR="@OPENJDK_TARGET_CPU_LIBDIR@" export DEBUG_LEVEL="@DEBUG_LEVEL@" From c4275c858c1129429fa72b33c993d0115f838317 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 28 Apr 2016 17:14:59 +0200 Subject: [PATCH 175/222] 8155629: MODULES_FILTER should apply to imported modules Reviewed-by: dholmes, tbell, mchung --- make/common/Modules.gmk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index dba855995d7..681c58ad07a 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -186,7 +186,8 @@ FindAllModules = \ $(call GetModuleNameFromModuleInfo, $(MODULE_INFOS)))) FindImportedModules = \ - $(if $(IMPORT_MODULES_CLASSES), $(notdir $(wildcard $(IMPORT_MODULES_CLASSES)/*))) + $(filter-out $(MODULES_FILTER), \ + $(if $(IMPORT_MODULES_CLASSES), $(notdir $(wildcard $(IMPORT_MODULES_CLASSES)/*)))) # Find all source dirs for a particular module # $1 - Module to find source dirs for From e9a10a4fcab03f47ae595ef210a50a0c5db69f12 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 28 Apr 2016 08:26:30 -0700 Subject: [PATCH 176/222] Added tag jdk-9+116 for changeset fbab762803ef --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 06edc4a1f53..fa57d754762 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -358,3 +358,4 @@ f900d5afd9c83a0df8f36161c27c5e4c86a66f4c jdk-9+111 55b6d550828d1223b364e6ead4a56e56411c56df jdk-9+113 1d992540870ff33fe6cc550443388588df9b9e4f jdk-9+114 09617ce980b99d49abfd54dacfed353c47e2a115 jdk-9+115 +6743a8e0cab7b5f6f4a0575f6664892f0ab740af jdk-9+116 From a78f72848016ffe0cb5c475c7f4884d79e283441 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 28 Apr 2016 08:26:32 -0700 Subject: [PATCH 177/222] Added tag jdk-9+116 for changeset e29791634c81 --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 11405727ce0..23786130f3e 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -518,3 +518,4 @@ c558850fac5750d8ca98a45180121980f57cdd28 jdk-9+111 c569f8d89269fb6205b90f727581eb8cc04132f9 jdk-9+113 b64432bae5271735fd53300b2005b713e98ef411 jdk-9+114 88dd08d7be0fe7fb9f1914b1628f0aae9bf56e25 jdk-9+115 +61a214186dae6811dd989e9165e42f7dbf02acde jdk-9+116 From 40edabdf12aa02c11adc929c7add31d9a451d2c2 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 28 Apr 2016 08:26:32 -0700 Subject: [PATCH 178/222] Added tag jdk-9+116 for changeset bff09f64dd1c --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index dd25acb220b..9b4adbd6b27 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -358,3 +358,4 @@ b75afa17aefe480c23c616a6a2497063312f7189 jdk-9+109 cc30faa2da498c478e89ab062ff160653ca1b170 jdk-9+113 10d175b0368c30f54350fc648adc41b94ce357ee jdk-9+114 7bab1b1b36824924b1c657a8419369ba93d198d3 jdk-9+115 +7dfa7377a5e601b8f740741a9a80e04c72dd04d6 jdk-9+116 From 61e4e8685db9e99adec7218c7150a1688f4a2afa Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 28 Apr 2016 08:26:36 -0700 Subject: [PATCH 179/222] Added tag jdk-9+116 for changeset 318476412bc2 --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 07b1b9985f7..53336dcb47a 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -358,3 +358,4 @@ bdbf2342b21bd8ecad1b4e6499a0dfb314952bd7 jdk-9+103 28626780e245fccbfb9bad8e3b05f62357958038 jdk-9+113 147114dd0641cd7c9fe6e81642eb993a7b9c6f0b jdk-9+114 1902a5bda18e794b31fc5f520f5e7d827714b50d jdk-9+115 +9d71d20e614777cd23c1a43b38b5c08a9094d27a jdk-9+116 From a0bed541c095c71dde3afd772d2550cff26c95c2 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 28 Apr 2016 08:26:36 -0700 Subject: [PATCH 180/222] Added tag jdk-9+116 for changeset f0cb22ad8db4 --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 7781746dc33..7ca8b5131a5 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -361,3 +361,4 @@ fafd694e801f0f5a7c737fb08630ced3ca8f772c jdk-9+107 e980062475c10d21137051045bf95ee229db9b27 jdk-9+113 b314bb02182b9ca94708a91f312c377f5435f740 jdk-9+114 4ff86e5489e4c0513dadfa69def8601c110ca5cd jdk-9+115 +529f0bf896e58525614d863e283ad155531941cb jdk-9+116 From 21311d2cb71798d52f0d6df9abf90bca8ba4ca2b Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 28 Apr 2016 08:26:38 -0700 Subject: [PATCH 181/222] Added tag jdk-9+116 for changeset d91c47cb2992 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 74ad9bf9055..68f3b996bfc 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -358,3 +358,4 @@ b2a69d66dc65ad1d3aeb3bd362cf5bb0deba040e jdk-9+111 68f8be44b6a6b33dfa841ec671c0ba6e4056b372 jdk-9+113 bb8379287f3736f38c52b2d1418784e2592461d1 jdk-9+114 35225b837d66582037eeadeb471c13235dfd793d jdk-9+115 +baeb5edb38939cdb78ae0ac6f4fd368465cbf188 jdk-9+116 From 8c52468e73f2a7d4bdb039b1e284620d0b162c6e Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 28 Apr 2016 08:26:42 -0700 Subject: [PATCH 182/222] Added tag jdk-9+116 for changeset 33cf53901cac --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index e8881f37c97..b45c9be6af7 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -358,3 +358,4 @@ f5991c73ed73b9a355a090b65c8d7fb9a1901f89 jdk-9+109 4e87682893e662421af10a62d29ae822ce0fea04 jdk-9+113 cba09a2e6ae969b029783eb59bb01017b78f8eef jdk-9+114 31c8b18fdc5b94a2ddd5ea0694f350a2c907e9f7 jdk-9+115 +3e3553ee39d9e081573bc7c88a252214a3152763 jdk-9+116 From 45082e319463fefcbb3f45c37a08a8eb29d65741 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 28 Apr 2016 08:26:43 -0700 Subject: [PATCH 183/222] Added tag jdk-9+116 for changeset 973b1c28c6d2 --- nashorn/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/nashorn/.hgtags b/nashorn/.hgtags index 78e30d77611..93b4c4a0b7c 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -349,3 +349,4 @@ c261f8440c5578b34596e6b0419a81aec431a884 jdk-9+112 a5d1990fd32d908da8154d79116fce8013ba4d40 jdk-9+113 ba21793a0e4816283cc0ecdab5142a4959363529 jdk-9+114 295ac208a4443d433214d0c1f32d2ea45a3a32d2 jdk-9+115 +208388a5622dcca8227d6ad6c268f2c88087d283 jdk-9+116 From 552f7b32c16bca29540c09940a9a93d85778d222 Mon Sep 17 00:00:00 2001 From: Chris Bensen Date: Thu, 28 Apr 2016 08:28:48 -0700 Subject: [PATCH 184/222] 8150990: Add helper class in jdk.jlink for packager use to avoid coordination with FX and JDK builds Reviewed-by: alanb, mchung, kcr, sundar --- .../packager/AppRuntimeImageBuilder.java | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java new file mode 100644 index 00000000000..fb785da54b7 --- /dev/null +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jlink.internal.packager; + + +import jdk.tools.jlink.Jlink; +import jdk.tools.jlink.builder.ImageBuilder; +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.builder.*; +import jdk.tools.jlink.plugin.Pool; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; +import java.util.stream.Collectors; + +/** + * AppRuntimeImageBuilder is a private API used only by the Java Packager to generate + * a Java runtime image using jlink. AppRuntimeImageBuilder encapsulates the + * arguments that jlink requires to generate this image. To create the image call the + * build() method. + */ +public final class AppRuntimeImageBuilder { + private Path outputDir = null; + private List modulePath = null; + private Set addModules = null; + private Set limitModules = null; + private String excludeFileList = null; + private Map userArguments = null; + private Boolean stripNativeCommands = null; + + public AppRuntimeImageBuilder() {} + + public void setOutputDir(Path value) { + outputDir = value; + } + + public void setModulePath(List value) { + modulePath = value; + } + + public void setAddModules(Set value) { + addModules = value; + } + + public void setLimitModules(Set value) { + limitModules = value; + } + + public void setExcludeFileList(String value) { + excludeFileList = value; + } + + public void setStripNativeCommands(boolean value) { + stripNativeCommands = value; + } + + public void setUserArguments(Map value) { + userArguments = value; + } + + public void build() throws IOException { + // jlink main arguments + Jlink.JlinkConfiguration jlinkConfig = new Jlink.JlinkConfiguration( + new File("").toPath(), // Unused + modulePath, addModules, limitModules); + + // plugin configuration + List plugins = new ArrayList(); + + if (stripNativeCommands) { + plugins.add(Jlink.newPlugin( + "strip-native-commands", + Collections.singletonMap("strip-native-commands", "on"), + null)); + } + + if (excludeFileList != null && !excludeFileList.isEmpty()) { + plugins.add(Jlink.newPlugin( + "exclude-files", + Collections.singletonMap("exclude-files", excludeFileList), + null)); + } + + // add user supplied jlink arguments + for (Map.Entry entry : userArguments.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + plugins.add(Jlink.newPlugin(key, + Collections.singletonMap(key, value), + null)); + } + + plugins.add(Jlink.newPlugin("installed-modules", Collections.emptyMap(), null)); + + // build the image + Jlink.PluginsConfiguration pluginConfig = new Jlink.PluginsConfiguration( + plugins, new DefaultImageBuilder(true, outputDir), null); + Jlink jlink = new Jlink(); + jlink.build(jlinkConfig, pluginConfig); + } +} From 8a708bda63d0dcbf0ed4bc87d5c1c58ad7821bbc Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 28 Apr 2016 17:33:49 +0200 Subject: [PATCH 185/222] 8155632: Remove debuginfo from jmod files Reviewed-by: tbell, mchung, alanb --- make/CreateJmods.gmk | 2 +- make/Images.gmk | 49 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk index fdfb7dc6884..212132779b1 100644 --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk @@ -82,7 +82,7 @@ $(IMAGES_OUTPUTDIR)/jmods/$(MODULE).jmod: $(DEPS) --os-version $(REQUIRED_OS_VERSION) \ --modulepath $(IMAGES_OUTPUTDIR)/jmods\ --hash-dependencies '.*' \ - --exclude '**_the.*' \ + --exclude '**{_the.*,*.diz,*.debuginfo,*.dSYM/**,*.pdb,*.map}' \ $(JMOD_FLAGS) $(SUPPORT_OUTPUTDIR)/jmods/$(notdir $@) $(MV) $(SUPPORT_OUTPUTDIR)/jmods/$(notdir $@) $@ diff --git a/make/Images.gmk b/make/Images.gmk index 97cce400395..a50cd7ca4d4 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -422,6 +422,55 @@ ifeq ($(GCOV_ENABLED), true) endif +################################################################################ +# Debug symbols +# Since debug symbols are not included in the jmod files, they need to be copied +# in manually after generating the images. + +ALL_JDK_MODULES := $(JDK_MODULES) +ALL_JRE_MODULES := $(sort $(JRE_MODULES), $(foreach m, $(JRE_MODULES), \ + $(call FindTransitiveDepsForModule, $m))) + +ifeq ($(OPENJDK_TARGET_OS), windows) + LIBS_TARGET_SUBDIR := bin +else + LIBS_TARGET_SUBDIR := lib +endif + +DEBUGINFO_SUFFIXES := .diz .debuginfo .pdb .map + +# Param 1 - dir to find debuginfo files in +FindDebuginfoFiles = \ + $(wildcard $(addprefix $1/*, $(DEBUGINFO_SUFFIXES)) \ + $(addprefix $1/*/*, $(DEBUGINFO_SUFFIXES)) \ + $(addprefix $1/*/*/*, $(DEBUGINFO_SUFFIXES))) + +# On Macosx, if debug symbols have not been zipped, find all files inside *.dSYM +# dirs. +ifeq ($(OPENJDK_TARGET_OS)-$(ZIP_EXTERNAL_DEBUG_SYMBOLS), macosx-false) + $(eval $(call FillCacheFind, \ + $(SUPPORT_OUTPUTDIR)/modules_cmds $(SUPPORT_OUTPUTDIR)/modules_libs/)) + FindDebuginfoFiles = \ + $(if $(wildcard $1), $(call containing, .dSYM/, $(call CacheFind, $1))) +endif + +# Param 1 - either JDK or JRE +SetupCopyDebuginfo = \ + $(foreach m, $(ALL_$1_MODULES), \ + $(eval $(call SetupCopyFiles, COPY_$1_LIBS_DEBUGINFO_$m, \ + SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/$m, \ + DEST := $($1_IMAGE_DIR)/$(LIBS_TARGET_SUBDIR), \ + FILES := $(call FindDebuginfoFiles, \ + $(SUPPORT_OUTPUTDIR)/modules_libs/$m), \ + )) \ + $(eval $1_TARGETS += $$(COPY_$1_LIBS_DEBUGINFO_$m)) \ + ) + +# No space before argument to avoid having to put $(strip ) everywhere in +# implementation above. +$(call SetupCopyDebuginfo,JDK) +$(call SetupCopyDebuginfo,JRE) + ################################################################################ # Include custom post hook here to make it possible to augment the target lists From 41a3e98a61292a2a382a44e81ab9d19c62c388f9 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Thu, 28 Apr 2016 10:41:53 -0500 Subject: [PATCH 186/222] 8153835: Fix range of flag MaxDirectMemorySize which is parsed at jlong Changed MaxDirectMemorySize type to uint64_t and set max to max_jlong Reviewed-by: goetz, simonis --- hotspot/src/share/vm/prims/jvm.cpp | 2 +- hotspot/src/share/vm/runtime/globals.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 5166478e5e7..2357ad7e80c 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -389,7 +389,7 @@ JVM_ENTRY(jobject, JVM_InitProperties(JNIEnv *env, jobject properties)) PUTPROP(props, "sun.nio.MaxDirectMemorySize", "-1"); } else { char as_chars[256]; - jio_snprintf(as_chars, sizeof(as_chars), SIZE_FORMAT, MaxDirectMemorySize); + jio_snprintf(as_chars, sizeof(as_chars), JULONG_FORMAT, MaxDirectMemorySize); PUTPROP(props, "sun.nio.MaxDirectMemorySize", as_chars); } } diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index bfc05242309..a3367fe1324 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3847,9 +3847,9 @@ public: \ /* Properties for Java libraries */ \ \ - product(size_t, MaxDirectMemorySize, 0, \ + product(uint64_t, MaxDirectMemorySize, 0, \ "Maximum total size of NIO direct-buffer allocations") \ - range(0, (size_t)SIZE_MAX) \ + range(0, max_jlong) \ \ /* Flags used for temporary code during development */ \ \ From 2f9ffbd2802e0a8ce7f02edc2fcaa17644135384 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Thu, 28 Apr 2016 09:08:01 -0700 Subject: [PATCH 187/222] 8154220: Semi-colon delimited list of catalog files in System property is throwing IllegalArgumentException Reviewed-by: lancea --- .../javax/xml/catalog/CatalogFeatures.java | 8 ++- .../jaxp/unittest/catalog/CatalogTest.java | 57 ++++++++++++++++++- .../xml/jaxp/unittest/catalog/first_cat.xml | 6 ++ .../xml/jaxp/unittest/catalog/next_cat.xml | 6 ++ .../xml/jaxp/unittest/catalog/second_cat.xml | 7 +++ 5 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 jaxp/test/javax/xml/jaxp/unittest/catalog/first_cat.xml create mode 100644 jaxp/test/javax/xml/jaxp/unittest/catalog/next_cat.xml create mode 100644 jaxp/test/javax/xml/jaxp/unittest/catalog/second_cat.xml diff --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java index 8cc0e53ae9e..72a88e2b2a2 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java @@ -444,13 +444,15 @@ public class CatalogFeatures { } } else if (index == Feature.FILES.ordinal()) { try { - if (Util.verifyAndGetURI(value, null) == null) { - CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, null); + String[] catalogFile = value.split(";[ ]*"); + for (String temp : catalogFile) { + if (Util.verifyAndGetURI(temp, null) == null) { + CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, null); + } } }catch (MalformedURLException | URISyntaxException | IllegalArgumentException ex) { CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, ex); } - } if (states[index] == null || state.compareTo(states[index]) >= 0) { values[index] = value; diff --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java index 7edd6af3503..01bf4f63e89 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java @@ -23,6 +23,7 @@ package catalog; import java.io.IOException; +import java.nio.file.Paths; import javax.xml.catalog.Catalog; import javax.xml.catalog.CatalogException; import javax.xml.catalog.CatalogFeatures; @@ -34,6 +35,7 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.testng.Assert; +import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.xml.sax.Attributes; @@ -44,10 +46,49 @@ import org.xml.sax.XMLReader; import org.xml.sax.ext.DefaultHandler2; /* - * @bug 8081248, 8144966, 8146606, 8146237, 8151154, 8150969, 8151162, 8152527 + * @bug 8081248, 8144966, 8146606, 8146237, 8151154, 8150969, 8151162, 8152527, 8154220 * @summary Tests basic Catalog functions. */ public class CatalogTest { + static final String KEY_FILES = "javax.xml.catalog.files"; + + public String filepath; + + /* + * Initializing fields + */ + @BeforeClass + public void setUpClass() throws Exception { + String file1 = getClass().getResource("first_cat.xml").getFile(); + if (System.getProperty("os.name").contains("Windows")) { + filepath = file1.substring(1, file1.lastIndexOf("/") + 1); + } else { + filepath = file1.substring(0, file1.lastIndexOf("/") + 1); + } + } + + /* + * @bug 8154220 + * Verifies that the file input is validated properly. Valid input includes + * multiple file paths separated by semicolon. + */ + @Test(dataProvider = "hierarchyOfCatFilesData") + public void hierarchyOfCatFiles2(String systemId, String expectedUri) { + String file1 = getClass().getResource("first_cat.xml").getFile(); + String file2 = getClass().getResource("second_cat.xml").getFile(); + String files = file1 + ";" + file2; + + try { + System.setProperty(KEY_FILES, files); + CatalogResolver catalogResolver = CatalogManager.catalogResolver(CatalogFeatures.defaults()); + String sysId = catalogResolver.resolveEntity(null, systemId).getSystemId(); + Assert.assertEquals(sysId, Paths.get(filepath + expectedUri).toUri().toString().replace("///", "/"), "System ID match not right"); + } finally { + System.clearProperty(KEY_FILES); + } + + } + /* * @bug 8152527 * This test is the same as the JDK test ResolveEntityTests:testMatch1. @@ -288,6 +329,19 @@ public class CatalogTest { } } + /* + DataProvider: used to verify hierarchical catalogs. Refer to JCK test + hierarchyOfCatFiles2. + */ + @DataProvider(name = "hierarchyOfCatFilesData") + Object[][] getHierarchyOfCatFilesData() { + return new Object[][]{ + {"http://www.oracle.com/sequence.dtd", "first.dtd"}, + {"http://www.oracle.com/sequence_next.dtd", "next.dtd"}, + {"http://www.oracle.com/sequence_second.dtd", "second.dtd"} + }; + } + /* DataProvider: used to verify CatalogResolver's resolveEntity function. Data columns: @@ -300,6 +354,7 @@ public class CatalogTest { {"rewriteSystem_id.xml", "system", "http://www.sys00test.com/rewrite.dtd", "PUB-404", expected, expected, "Relative rewriteSystem with xml:base at group level failed"}, }; } + static String id = "http://openjdk.java.net/xml/catalog/dtd/system.dtd"; /* DataProvider: used to verify how prefer settings affect the result of the diff --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/first_cat.xml b/jaxp/test/javax/xml/jaxp/unittest/catalog/first_cat.xml new file mode 100644 index 00000000000..545be010596 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/first_cat.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/next_cat.xml b/jaxp/test/javax/xml/jaxp/unittest/catalog/next_cat.xml new file mode 100644 index 00000000000..b8adc372248 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/next_cat.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/second_cat.xml b/jaxp/test/javax/xml/jaxp/unittest/catalog/second_cat.xml new file mode 100644 index 00000000000..c23bfc39abe --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/second_cat.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From 0c5f058520b6263c0b3a75bd5ef65d66221c6889 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Thu, 28 Apr 2016 12:25:16 -0700 Subject: [PATCH 188/222] 8153190: JVMTI GetAllModules should make it clear that it also returns unnamed module Clarify the JVMTI spec Reviewed-by: alanb --- hotspot/src/share/vm/prims/jvmti.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml index f6a18c771ac..067a8aceb97 100644 --- a/hotspot/src/share/vm/prims/jvmti.xml +++ b/hotspot/src/share/vm/prims/jvmti.xml @@ -6482,6 +6482,7 @@ class C2 extends C1 implements I2 { Get All Modules Return an array of all modules loaded in the virtual machine. + The array includes the unnamed module for each class loader. The number of modules in the array is returned via module_count_ptr, and the array itself via modules_ptr. From 93a8bd38432584135ee12aaa9fda06ce9eb0e58c Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Thu, 28 Apr 2016 14:29:09 -0700 Subject: [PATCH 189/222] 8154801: deprecate Observer and Observable Reviewed-by: darcy --- .../share/classes/java/util/Observable.java | 14 +++++++++++++- .../share/classes/java/util/Observer.java | 7 ++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/Observable.java b/jdk/src/java.base/share/classes/java/util/Observable.java index cff9e1f4d7b..b19830bb64e 100644 --- a/jdk/src/java.base/share/classes/java/util/Observable.java +++ b/jdk/src/java.base/share/classes/java/util/Observable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,19 @@ package java.util; * @see java.util.Observer * @see java.util.Observer#update(java.util.Observable, java.lang.Object) * @since 1.0 + * + * @deprecated + * This class and the {@link Observer} interface have been deprecated. + * The event model supported by {@code Observer} and {@code Observable} + * is quite limited, the order of notifications delivered by + * {@code Observable} is unspecified, and state changes are not in + * one-for-one correspondence with notifications. + * For a richer event model, consider using the + * {@link java.beans} package. For reliable and ordered + * messaging among threads, consider using one of the concurrent data + * structures in the {@link java.util.concurrent} package. */ +@Deprecated(since="9") public class Observable { private boolean changed = false; private Vector obs; diff --git a/jdk/src/java.base/share/classes/java/util/Observer.java b/jdk/src/java.base/share/classes/java/util/Observer.java index 2db27b44a2d..47f793376ab 100644 --- a/jdk/src/java.base/share/classes/java/util/Observer.java +++ b/jdk/src/java.base/share/classes/java/util/Observer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * 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,12 @@ package java.util; * @author Chris Warth * @see java.util.Observable * @since 1.0 + * + * @deprecated + * This interface has been deprecated. See the {@link Observable} + * class for further information. */ +@Deprecated(since="9") public interface Observer { /** * This method is called whenever the observed object is changed. An From 766c5e26ae93431d850d392b0278d60237877c99 Mon Sep 17 00:00:00 2001 From: Frank Yuan Date: Thu, 28 Apr 2016 19:11:09 -0700 Subject: [PATCH 190/222] 8155514: jaxp.library.TestPolicy should extend the default security policy Reviewed-by: mchung, joehw --- jaxp/test/javax/xml/jaxp/libs/jaxp/library/TestPolicy.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/test/javax/xml/jaxp/libs/jaxp/library/TestPolicy.java b/jaxp/test/javax/xml/jaxp/libs/jaxp/library/TestPolicy.java index 1e39fbc36eb..a1922a7cc51 100644 --- a/jaxp/test/javax/xml/jaxp/libs/jaxp/library/TestPolicy.java +++ b/jaxp/test/javax/xml/jaxp/libs/jaxp/library/TestPolicy.java @@ -91,6 +91,7 @@ public class TestPolicy extends Policy { permissions.add(new PropertyPermission("line.separator", "read")); permissions.add(new PropertyPermission("fileStringBuffer", "read")); permissions.add(new PropertyPermission("dataproviderthreadcount", "read")); + permissions.add(new RuntimePermission("charsetProvider")); } /* From 9950f584d0fc339300eef9c76096756a37dc9f47 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Fri, 29 Apr 2016 01:45:35 -0400 Subject: [PATCH 191/222] 8155689: Build failing for install on jdk9/dev when using -testset hotspot Add installer target that aliases the expected target Reviewed-by: jmasa, tbell --- make/Main.gmk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/make/Main.gmk b/make/Main.gmk index 3d596817c08..43a6f755ec0 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -831,6 +831,10 @@ create-main-targets-include: ################################################################################ + +# workaround issue when building open targets when closed jib-profiles.js is used +installer: product-images test-image + .PHONY: $(ALL_TARGETS) FRC: # Force target From 46e74c829b39a54ddb44e105bd3d750412a5f9af Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Fri, 29 Apr 2016 11:56:31 +0200 Subject: [PATCH 192/222] 8155036: Remove sun.security.action.GetBooleanSecurityPropertyAction Reviewed-by: mullan, mchung, chegar --- .../GetBooleanSecurityPropertyAction.java | 74 ------------------- 1 file changed, 74 deletions(-) delete mode 100644 jdk/src/java.base/share/classes/sun/security/action/GetBooleanSecurityPropertyAction.java diff --git a/jdk/src/java.base/share/classes/sun/security/action/GetBooleanSecurityPropertyAction.java b/jdk/src/java.base/share/classes/sun/security/action/GetBooleanSecurityPropertyAction.java deleted file mode 100644 index 9b180f1bdfd..00000000000 --- a/jdk/src/java.base/share/classes/sun/security/action/GetBooleanSecurityPropertyAction.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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. 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 sun.security.action; - -import java.security.Security; - -/** - * A convenience class for retrieving the boolean value of a security property - * as a privileged action. - * - *

      An instance of this class can be used as the argument of - * AccessController.doPrivileged. - * - *

      The following code retrieves the boolean value of the security - * property named "prop" as a privileged action: - * - *

      - * boolean b = java.security.AccessController.doPrivileged
      - *              (new GetBooleanSecurityPropertyAction("prop")).booleanValue();
      - * 
      - * - */ -public class GetBooleanSecurityPropertyAction - implements java.security.PrivilegedAction { - private String theProp; - - /** - * Constructor that takes the name of the security property whose boolean - * value needs to be determined. - * - * @param theProp the name of the security property - */ - public GetBooleanSecurityPropertyAction(String theProp) { - this.theProp = theProp; - } - - /** - * Determines the boolean value of the security property whose name was - * specified in the constructor. - * - * @return the Boolean value of the security property. - */ - public Boolean run() { - boolean b = false; - try { - String value = Security.getProperty(theProp); - b = (value != null) && value.equalsIgnoreCase("true"); - } catch (NullPointerException e) {} - return b; - } -} From a6f2cdbb0f6a6058eb3dac64dc08259fa594cfc3 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 29 Apr 2016 13:24:27 +0300 Subject: [PATCH 193/222] 8155090: String concatenation fails with a custom SecurityManager that uses concatenation Reviewed-by: redestad, chegar --- .../java/lang/invoke/StringConcatFactory.java | 12 ++++- .../String/concat/WithSecurityManager.java | 53 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/lang/String/concat/WithSecurityManager.java diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 44f29a4a136..f302c75af79 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -123,7 +123,7 @@ public final class StringConcatFactory { * Concatenation strategy to use. See {@link Strategy} for possible options. * This option is controllable with -Djava.lang.invoke.stringConcat JDK option. */ - private static final Strategy STRATEGY; + private static Strategy STRATEGY; /** * Default strategy to use for concatenation. @@ -187,6 +187,16 @@ public final class StringConcatFactory { private static final ProxyClassesDumper DUMPER; static { + // In case we need to double-back onto the StringConcatFactory during this + // static initialization, make sure we have the reasonable defaults to complete + // the static initialization properly. After that, actual users would use the + // the proper values we have read from the the properties. + STRATEGY = DEFAULT_STRATEGY; + // CACHE_ENABLE = false; // implied + // CACHE = null; // implied + // DEBUG = false; // implied + // DUMPER = null; // implied + Properties props = GetPropertyAction.getProperties(); final String strategy = props.getProperty("java.lang.invoke.stringConcat"); diff --git a/jdk/test/java/lang/String/concat/WithSecurityManager.java b/jdk/test/java/lang/String/concat/WithSecurityManager.java new file mode 100644 index 00000000000..17fc437ff3f --- /dev/null +++ b/jdk/test/java/lang/String/concat/WithSecurityManager.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. + * 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.security.Permission; + +/** + * @test + * @summary String concatenation fails with a custom SecurityManager that uses concatenation + * @bug 8155090 + * + * @compile WithSecurityManager.java + * + * @run main/othervm -Xverify:all WithSecurityManager + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB WithSecurityManager + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED WithSecurityManager + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED WithSecurityManager + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT WithSecurityManager + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT WithSecurityManager + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT WithSecurityManager +*/ +public class WithSecurityManager { + public static void main(String[] args) throws Throwable { + SecurityManager sm = new SecurityManager() { + @Override + public void checkPermission(Permission perm) { + String abc = "abc"; + String full = abc + "def"; + } + }; + System.setSecurityManager(sm); + ClassLoader cl = new ClassLoader() {}; + } +} From 6db653621d80697ea9f0c9863f9d4897dee7a08f Mon Sep 17 00:00:00 2001 From: "Tagir F. Valeev" Date: Fri, 29 Apr 2016 16:52:05 +0300 Subject: [PATCH 194/222] 8155600: Performance optimization of Arrays.asList().iterator() Reviewed-by: redestad, shade, plevart, attila --- .../share/classes/java/util/Arrays.java | 31 ++++++- jdk/test/java/util/Arrays/AsList.java | 93 +++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/util/Arrays/AsList.java diff --git a/jdk/src/java.base/share/classes/java/util/Arrays.java b/jdk/src/java.base/share/classes/java/util/Arrays.java index cc7b19de64e..6d7e858fbed 100644 --- a/jdk/src/java.base/share/classes/java/util/Arrays.java +++ b/jdk/src/java.base/share/classes/java/util/Arrays.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -4403,6 +4403,35 @@ public class Arrays { public void sort(Comparator c) { Arrays.sort(a, c); } + + @Override + public Iterator iterator() { + return new ArrayItr<>(a); + } + } + + private static class ArrayItr implements Iterator { + private int cursor; + private final E[] a; + + ArrayItr(E[] a) { + this.a = a; + } + + @Override + public boolean hasNext() { + return cursor < a.length; + } + + @Override + public E next() { + int i = cursor; + if (i >= a.length) { + throw new NoSuchElementException(); + } + cursor = i + 1; + return a[i]; + } } /** diff --git a/jdk/test/java/util/Arrays/AsList.java b/jdk/test/java/util/Arrays/AsList.java new file mode 100644 index 00000000000..c64c473a822 --- /dev/null +++ b/jdk/test/java/util/Arrays/AsList.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8155600 + * @summary Tests for Arrays.asList() + * @run testng AsList + */ + +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.stream.IntStream; + +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.fail; + +public class AsList { + /* + * Iterator contract test + */ + @Test(dataProvider = "Arrays") + public void testIterator(Object[] array) { + Iterator itr = Arrays.asList(array).iterator(); + for (int i = 0; i < array.length; i++) { + assertTrue(itr.hasNext()); + assertTrue(itr.hasNext()); // must be idempotent + assertSame(array[i], itr.next()); + try { + itr.remove(); + fail("Remove must throw"); + } catch (UnsupportedOperationException ex) { + // expected + } + } + assertFalse(itr.hasNext()); + for (int i = 0; i < 3; i++) { + assertFalse(itr.hasNext()); + try { + itr.next(); + fail("Next succeed when there's no data left"); + } catch (NoSuchElementException ex) { + // expected + } + } + } + + @DataProvider(name = "Arrays") + public static Object[][] arrays() { + Object[][] arrays = { + { new Object[] { } }, + { new Object[] { 1 } }, + { new Object[] { null } }, + { new Object[] { null, 1 } }, + { new Object[] { 1, null } }, + { new Object[] { null, null } }, + { new Object[] { null, 1, 2 } }, + { new Object[] { 1, null, 2 } }, + { new Object[] { 1, 2, null } }, + { new Object[] { null, null, null } }, + { new Object[] { 1, 2, 3, null, 4 } }, + { new Object[] { "a", "a", "a", "a" } }, + { IntStream.range(0, 100).boxed().toArray() } + }; + + return arrays; + } +} From 88fc3658cc381b176adfe1028fb431a8e31cf1c9 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Fri, 29 Apr 2016 09:45:46 -0700 Subject: [PATCH 195/222] 8155606: [PIT] Robot's createScreenCapture() broken on Linux Reviewed-by: prr --- jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c index 91ad2515a8a..0e06972207f 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c @@ -265,7 +265,7 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, if (isGtkSupported) { gtk->gdk_threads_enter(); gtk_failed = gtk->get_drawable_data(env, pixelArray, x, y, width, - jwidth, height, dx, dy, scale); + height, jwidth, dx, dy, scale); gtk->gdk_threads_leave(); } From 6ec92b138948df30276c9d99ce2dafea89e9db46 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Fri, 29 Apr 2016 09:46:14 -0700 Subject: [PATCH 196/222] 8155613: [PIT] crash in AWT_Desktop/Automated/Exceptions/BasicTest Reviewed-by: prr --- .../java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c | 1 + .../java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c | 1 + 2 files changed, 2 insertions(+) diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c index 672a8414d8d..42408da5bbb 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c @@ -442,6 +442,7 @@ static gboolean gtk2_show_uri_load(JNIEnv *env) { fprintf(stderr, "dlsym(gtk_show_uri) returned NULL\n"); #endif /* DEBUG */ } else { + gtk->gtk_show_uri = fp_gtk_show_uri; update_supported_actions(env); success = TRUE; } diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c index 385c8015046..6a188fb3598 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c @@ -195,6 +195,7 @@ static gboolean gtk3_show_uri_load(JNIEnv *env) { fprintf(stderr, "dlsym(gtk_show_uri) returned NULL\n"); #endif /* DEBUG */ } else { + gtk->gtk_show_uri = fp_gtk_show_uri; update_supported_actions(env); success = TRUE; } From 4d3fe6b205091c212e089187909131de0f324706 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 29 Apr 2016 23:15:15 +0300 Subject: [PATCH 197/222] 8155215: java.lang.String concatenation spec is unnecessarily strong Reviewed-by: abuckley, sherman, chegar --- .../share/classes/java/lang/String.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/String.java b/jdk/src/java.base/share/classes/java/lang/String.java index a1772977727..64299b92337 100644 --- a/jdk/src/java.base/share/classes/java/lang/String.java +++ b/jdk/src/java.base/share/classes/java/lang/String.java @@ -78,14 +78,8 @@ import jdk.internal.vm.annotation.Stable; *

      * The Java language provides special support for the string * concatenation operator ( + ), and for conversion of - * other objects to strings. String concatenation is implemented - * through the {@code StringBuilder}(or {@code StringBuffer}) - * class and its {@code append} method. - * String conversions are implemented through the method - * {@code toString}, defined by {@code Object} and - * inherited by all classes in Java. For additional information on - * string concatenation and conversion, see Gosling, Joy, and Steele, - * The Java Language Specification. + * other objects to strings. For additional information on string + * concatenation and conversion, see The Java™ Language Specification. * *

      Unless otherwise noted, passing a {@code null} argument to a constructor * or method in this class will cause a {@link NullPointerException} to be @@ -106,6 +100,14 @@ import jdk.internal.vm.annotation.Stable; * into account. The {@link java.text.Collator} class provides methods for * finer-grain, locale-sensitive String comparison. * + * @implNote The implementation of the string concatenation operator is left to + * the discretion of a Java compiler, as long as the compiler ultimately conforms + * to The Java™ Language Specification. For example, the {@code javac} compiler + * may implement the operator with {@code StringBuffer}, {@code StringBuilder}, + * or {@code java.lang.invoke.StringConcatFactory} depending on the JDK version. The + * implementation of string conversion is typically through the method {@code toString}, + * defined by {@code Object} and inherited by all classes in Java. + * * @author Lee Boynton * @author Arthur van Hoff * @author Martin Buchholz From e955660cf18082234159590fef00f6d507db2db8 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Fri, 29 Apr 2016 13:46:19 -0700 Subject: [PATCH 198/222] 8154755: Add a VarHandle weakCompareAndSet with volatile semantics Reviewed-by: shade, vlivanov --- .../classes/java/lang/invoke/VarHandle.java | 136 ++++++++++++------ .../lang/invoke/X-VarHandle.java.template | 32 +++++ .../X-VarHandleByteArrayView.java.template | 20 +++ .../invoke/VarHandles/VarHandleBaseTest.java | 1 + .../VarHandleTestAccessBoolean.java | 21 +++ .../VarHandles/VarHandleTestAccessByte.java | 21 +++ .../VarHandles/VarHandleTestAccessChar.java | 21 +++ .../VarHandles/VarHandleTestAccessDouble.java | 21 +++ .../VarHandles/VarHandleTestAccessFloat.java | 21 +++ .../VarHandles/VarHandleTestAccessInt.java | 46 ++++-- .../VarHandles/VarHandleTestAccessLong.java | 46 ++++-- .../VarHandles/VarHandleTestAccessShort.java | 21 +++ .../VarHandles/VarHandleTestAccessString.java | 46 ++++-- .../VarHandleTestByteArrayAsChar.java | 13 ++ .../VarHandleTestByteArrayAsDouble.java | 47 +++++- .../VarHandleTestByteArrayAsFloat.java | 47 +++++- .../VarHandleTestByteArrayAsInt.java | 51 +++++-- .../VarHandleTestByteArrayAsLong.java | 47 +++++- .../VarHandleTestByteArrayAsShort.java | 13 ++ .../VarHandleTestMethodHandleAccessInt.java | 41 ++++-- .../VarHandleTestMethodHandleAccessLong.java | 41 ++++-- ...VarHandleTestMethodHandleAccessString.java | 41 ++++-- .../VarHandleTestMethodTypeInt.java | 72 ++++++++++ .../VarHandleTestMethodTypeLong.java | 72 ++++++++++ .../VarHandleTestMethodTypeString.java | 72 ++++++++++ .../X-VarHandleTestAccess.java.template | 67 +++++++-- ...X-VarHandleTestByteArrayView.java.template | 60 +++++++- ...HandleTestMethodHandleAccess.java.template | 41 ++++-- .../X-VarHandleTestMethodType.java.template | 72 ++++++++++ 29 files changed, 1098 insertions(+), 152 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java index cf869b3ebe7..4eb7f260a6c 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java @@ -136,6 +136,7 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError; * consists of the methods * {@link #compareAndSet compareAndSet}, * {@link #weakCompareAndSet weakCompareAndSet}, + * {@link #weakCompareAndSetVolatile weakCompareAndSetVolatile}, * {@link #weakCompareAndSetAcquire weakCompareAndSetAcquire}, * {@link #weakCompareAndSetRelease weakCompareAndSetRelease}, * {@link #compareAndExchangeAcquire compareAndExchangeAcquire}, @@ -458,7 +459,7 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code get} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.get)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.GET)} on this VarHandle. * *

      This access mode is supported by all VarHandle instances and never * throws {@code UnsupportedOperationException}. @@ -488,7 +489,7 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code set} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.set)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.SET)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T newValue)} @@ -516,7 +517,8 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code getVolatile} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.getVolatile)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.GET_VOLATILE)} on this + * VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT)} @@ -544,7 +546,8 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code setVolatile} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.setVolatile)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.SET_VOLATILE)} on this + * VarHandle. * * @apiNote * Ignoring the many semantic differences from C and C++, this method has @@ -574,7 +577,8 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code getOpaque} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.getOpaque)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.GET_OPAQUE)} on this + * VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT)} @@ -603,7 +607,8 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code setOpaque} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.setOpaque)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.SET_OPAQUE)} on this + * VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T newValue)} @@ -631,7 +636,8 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code getAcquire} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.getAcquire)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.GET_ACQUIRE)} on this + * VarHandle. * * @apiNote * Ignoring the many semantic differences from C and C++, this method has @@ -664,7 +670,8 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code setRelease} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.setRelease)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.SET_RELEASE)} on this + * VarHandle. * * @apiNote * Ignoring the many semantic differences from C and C++, this method has @@ -700,7 +707,7 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code * compareAndSet} must match the access mode type that is the result of - * calling {@code accessModeType(VarHandle.AccessMode.compareAndSet)} on + * calling {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_SET)} on * this VarHandle. * * @param args the signature-polymorphic parameter list of the form @@ -734,7 +741,7 @@ public abstract class VarHandle { *

      The symbolic type descriptor at the call site of {@code * compareAndExchangeVolatile} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.compareAndExchangeVolatile)} + * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_VOLATILE)} * on this VarHandle. * * @param args the signature-polymorphic parameter list of the form @@ -769,7 +776,7 @@ public abstract class VarHandle { *

      The symbolic type descriptor at the call site of {@code * compareAndExchangeAcquire} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.compareAndExchangeAcquire)} on + * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)} on * this VarHandle. * * @param args the signature-polymorphic parameter list of the form @@ -804,7 +811,8 @@ public abstract class VarHandle { *

      The symbolic type descriptor at the call site of {@code * compareAndExchangeRelease} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.compareAndExchangeRelease)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)} + * on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} @@ -836,14 +844,14 @@ public abstract class VarHandle { * {@link #get}. * *

      This operation may fail spuriously (typically, due to memory - * contention) even if the current value does match the expected value. + * contention) even if the witness value does match the expected value. * *

      The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}. * *

      The symbolic type descriptor at the call site of {@code * weakCompareAndSet} must match the access mode type that is the result of - * calling {@code accessModeType(VarHandle.AccessMode.weakCompareAndSet)} on - * this VarHandle. + * calling {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)} + * on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} @@ -865,6 +873,43 @@ public abstract class VarHandle { @HotSpotIntrinsicCandidate boolean weakCompareAndSet(Object... args); + /** + * Possibly atomically sets the value of a variable to the {@code newValue} + * with the memory semantics of {@link #setVolatile} if the variable's + * current value, referred to as the witness value, {@code ==} the + * {@code expectedValue}, as accessed with the memory semantics of + * {@link #getVolatile}. + * + *

      This operation may fail spuriously (typically, due to memory + * contention) even if the witness value does match the expected value. + * + *

      The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}. + * + *

      The symbolic type descriptor at the call site of {@code + * weakCompareAndSetVolatile} must match the access mode type that is the + * result of calling {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)} + * on this VarHandle. + * + * @param args the signature-polymorphic parameter list of the form + * {@code (CT, T expectedValue, T newValue)} + * , statically represented using varargs. + * @return {@code true} if successful, otherwise {@code false} if the + * witness value was not the same as the {@code expectedValue} or if this + * operation spuriously failed. + * @throws UnsupportedOperationException if the access mode is unsupported + * for this VarHandle. + * @throws WrongMethodTypeException if the access mode type is not + * compatible with the caller's symbolic type descriptor. + * @throws ClassCastException if the access mode type is compatible with the + * caller's symbolic type descriptor, but a reference cast fails. + * @see #setVolatile(Object...) + * @see #getVolatile(Object...) + */ + public final native + @MethodHandle.PolymorphicSignature + @HotSpotIntrinsicCandidate + boolean weakCompareAndSetVolatile(Object... args); + /** * Possibly atomically sets the value of a variable to the {@code newValue} * with the semantics of {@link #set} if the variable's current value, @@ -873,14 +918,15 @@ public abstract class VarHandle { * {@link #getAcquire}. * *

      This operation may fail spuriously (typically, due to memory - * contention) even if the current value does match the expected value. + * contention) even if the witness value does match the expected value. * *

      The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}. * *

      The symbolic type descriptor at the call site of {@code * weakCompareAndSetAcquire} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.weakCompareAndSetAcquire)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)} + * on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} @@ -910,14 +956,15 @@ public abstract class VarHandle { * {@link #get}. * *

      This operation may fail spuriously (typically, due to memory - * contention) even if the current value does match the expected value. + * contention) even if the witness value does match the expected value. * *

      The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}. * *

      The symbolic type descriptor at the call site of {@code * weakCompareAndSetRelease} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.weakCompareAndSetRelease)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)} + * on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} @@ -949,7 +996,8 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code getAndSet} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.getAndSet)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.GET_AND_SET)} on this + * VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T newValue)} @@ -985,7 +1033,8 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code getAndAdd} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.getAndAdd)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.GET_AND_ADD)} on this + * VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T value)} @@ -1017,7 +1066,8 @@ public abstract class VarHandle { * *

      The symbolic type descriptor at the call site of {@code addAndGet} * must match the access mode type that is the result of calling - * {@code accessModeType(VarHandle.AccessMode.addAndGet)} on this VarHandle. + * {@code accessModeType(VarHandle.AccessMode.ADD_AND_GET)} on this + * VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T value)} @@ -1083,109 +1133,115 @@ public abstract class VarHandle { * method * {@link VarHandle#get VarHandle.get} */ - GET("get", AccessType.GET, Object.class), // 0 + GET("get", AccessType.GET, Object.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#set VarHandle.set} */ - SET("set", AccessType.SET, void.class), // 1 + SET("set", AccessType.SET, void.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#getVolatile VarHandle.getVolatile} */ - GET_VOLATILE("getVolatile", AccessType.GET, Object.class), // 2 + GET_VOLATILE("getVolatile", AccessType.GET, Object.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#setVolatile VarHandle.setVolatile} */ - SET_VOLATILE("setVolatile", AccessType.SET, void.class), // 3 + SET_VOLATILE("setVolatile", AccessType.SET, void.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#getAcquire VarHandle.getAcquire} */ - GET_ACQUIRE("getAcquire", AccessType.GET, Object.class), // 4 + GET_ACQUIRE("getAcquire", AccessType.GET, Object.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#setRelease VarHandle.setRelease} */ - SET_RELEASE("setRelease", AccessType.SET, void.class), // 5 + SET_RELEASE("setRelease", AccessType.SET, void.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#getOpaque VarHandle.getOpaque} */ - GET_OPAQUE("getOpaque", AccessType.GET, Object.class), // 6 + GET_OPAQUE("getOpaque", AccessType.GET, Object.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#setOpaque VarHandle.setOpaque} */ - SET_OPAQUE("setOpaque", AccessType.SET, void.class), // 7 + SET_OPAQUE("setOpaque", AccessType.SET, void.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#compareAndSet VarHandle.compareAndSet} */ - COMPARE_AND_SET("compareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class), // 8 + COMPARE_AND_SET("compareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#compareAndExchangeVolatile VarHandle.compareAndExchangeVolatile} */ - COMPARE_AND_EXCHANGE_VOLATILE("compareAndExchangeVolatile", AccessType.COMPARE_AND_EXCHANGE, Object.class), // 9 + COMPARE_AND_EXCHANGE_VOLATILE("compareAndExchangeVolatile", AccessType.COMPARE_AND_EXCHANGE, Object.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#compareAndExchangeAcquire VarHandle.compareAndExchangeAcquire} */ - COMPARE_AND_EXCHANGE_ACQUIRE("compareAndExchangeAcquire", AccessType.COMPARE_AND_EXCHANGE, Object.class), // 10 + COMPARE_AND_EXCHANGE_ACQUIRE("compareAndExchangeAcquire", AccessType.COMPARE_AND_EXCHANGE, Object.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#compareAndExchangeRelease VarHandle.compareAndExchangeRelease} */ - COMPARE_AND_EXCHANGE_RELEASE("compareAndExchangeRelease", AccessType.COMPARE_AND_EXCHANGE, Object.class), // 11 + COMPARE_AND_EXCHANGE_RELEASE("compareAndExchangeRelease", AccessType.COMPARE_AND_EXCHANGE, Object.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#weakCompareAndSet VarHandle.weakCompareAndSet} */ - WEAK_COMPARE_AND_SET("weakCompareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class), // 12 + WEAK_COMPARE_AND_SET("weakCompareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class), + /** + * The access mode whose access is specified by the corresponding + * method + * {@link VarHandle#weakCompareAndSetVolatile VarHandle.weakCompareAndSetVolatile} + */ + WEAK_COMPARE_AND_SET_VOLATILE("weakCompareAndSetVolatile", AccessType.COMPARE_AND_SWAP, boolean.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#weakCompareAndSetAcquire VarHandle.weakCompareAndSetAcquire} */ - WEAK_COMPARE_AND_SET_ACQUIRE("weakCompareAndSetAcquire", AccessType.COMPARE_AND_SWAP, boolean.class), // 13 + WEAK_COMPARE_AND_SET_ACQUIRE("weakCompareAndSetAcquire", AccessType.COMPARE_AND_SWAP, boolean.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#weakCompareAndSetRelease VarHandle.weakCompareAndSetRelease} */ - WEAK_COMPARE_AND_SET_RELEASE("weakCompareAndSetRelease", AccessType.COMPARE_AND_SWAP, boolean.class), // 14 + WEAK_COMPARE_AND_SET_RELEASE("weakCompareAndSetRelease", AccessType.COMPARE_AND_SWAP, boolean.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#getAndSet VarHandle.getAndSet} */ - GET_AND_SET("getAndSet", AccessType.GET_AND_UPDATE, Object.class), // 15 + GET_AND_SET("getAndSet", AccessType.GET_AND_UPDATE, Object.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#getAndAdd VarHandle.getAndAdd} */ - GET_AND_ADD("getAndAdd", AccessType.GET_AND_UPDATE, Object.class), // 16 + GET_AND_ADD("getAndAdd", AccessType.GET_AND_UPDATE, Object.class), /** * The access mode whose access is specified by the corresponding * method * {@link VarHandle#addAndGet VarHandle.addAndGet} */ - ADD_AND_GET("addAndGet", AccessType.GET_AND_UPDATE, Object.class), // 17 + ADD_AND_GET("addAndGet", AccessType.GET_AND_UPDATE, Object.class), ; static final Map methodNameToAccessMode; diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template index bcec64bd390..4a9d9e11e36 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template +++ b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template @@ -154,6 +154,15 @@ final class VarHandle$Type$s { {#if[Object]?handle.fieldType.cast(value):value}); } + @ForceInline + static boolean weakCompareAndSetVolatile(FieldInstanceReadWrite handle, Object holder, $type$ expected, $type$ value) { + // TODO defer to strong form until new Unsafe method is added + return UNSAFE.compareAndSwap$Type$(Objects.requireNonNull(handle.receiverType.cast(holder)), + handle.fieldOffset, + {#if[Object]?handle.fieldType.cast(expected):expected}, + {#if[Object]?handle.fieldType.cast(value):value}); + } + @ForceInline static boolean weakCompareAndSetAcquire(FieldInstanceReadWrite handle, Object holder, $type$ expected, $type$ value) { return UNSAFE.weakCompareAndSwap$Type$Acquire(Objects.requireNonNull(handle.receiverType.cast(holder)), @@ -318,6 +327,15 @@ final class VarHandle$Type$s { {#if[Object]?handle.fieldType.cast(value):value}); } + @ForceInline + static boolean weakCompareAndSetVolatile(FieldStaticReadWrite handle, $type$ expected, $type$ value) { + // TODO defer to strong form until new Unsafe method is added + return UNSAFE.compareAndSwap$Type$(handle.base, + handle.fieldOffset, + {#if[Object]?handle.fieldType.cast(expected):expected}, + {#if[Object]?handle.fieldType.cast(value):value}); + } + @ForceInline static boolean weakCompareAndSetAcquire(FieldStaticReadWrite handle, $type$ expected, $type$ value) { return UNSAFE.weakCompareAndSwap$Type$Acquire(handle.base, @@ -534,6 +552,20 @@ final class VarHandle$Type$s { {#if[Object]?handle.componentType.cast(value):value}); } + @ForceInline + static boolean weakCompareAndSetVolatile(Array handle, Object oarray, int index, $type$ expected, $type$ value) { +#if[Object] + Object[] array = (Object[]) handle.arrayType.cast(oarray); +#else[Object] + $type$[] array = ($type$[]) oarray; +#end[Object] + // TODO defer to strong form until new Unsafe method is added + return UNSAFE.compareAndSwap$Type$(array, + (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + {#if[Object]?handle.componentType.cast(expected):expected}, + {#if[Object]?handle.componentType.cast(value):value}); + } + @ForceInline static boolean weakCompareAndSetAcquire(Array handle, Object oarray, int index, $type$ expected, $type$ value) { #if[Object] diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template index bdc77a820d2..b5bf9cba232 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template +++ b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template @@ -227,6 +227,16 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { convEndian(handle.be, expected), convEndian(handle.be, value)); } + @ForceInline + static boolean weakCompareAndSetVolatile(ArrayHandle handle, Object oba, int index, $type$ expected, $type$ value) { + byte[] ba = (byte[]) oba; + // TODO defer to strong form until new Unsafe method is added + return UNSAFE.compareAndSwap$RawType$( + ba, + address(ba, index(ba, index)), + convEndian(handle.be, expected), convEndian(handle.be, value)); + } + @ForceInline static boolean weakCompareAndSetAcquire(ArrayHandle handle, Object oba, int index, $type$ expected, $type$ value) { byte[] ba = (byte[]) oba; @@ -443,6 +453,16 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { convEndian(handle.be, expected), convEndian(handle.be, value)); } + @ForceInline + static boolean weakCompareAndSetVolatile(ByteBufferHandle handle, Object obb, int index, $type$ expected, $type$ value) { + ByteBuffer bb = (ByteBuffer) obb; + // TODO defer to strong form until new Unsafe method is added + return UNSAFE.compareAndSwap$RawType$( + UNSAFE.getObject(bb, BYTE_BUFFER_HB), + address(bb, indexRO(bb, index)), + convEndian(handle.be, expected), convEndian(handle.be, value)); + } + @ForceInline static boolean weakCompareAndSetAcquire(ByteBufferHandle handle, Object obb, int index, $type$ expected, $type$ value) { ByteBuffer bb = (ByteBuffer) obb; diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleBaseTest.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleBaseTest.java index 241d821c00a..59737dbeb7b 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleBaseTest.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleBaseTest.java @@ -148,6 +148,7 @@ abstract class VarHandleBaseTest { COMPARE_AND_EXCHANGE_ACQUIRE(TestAccessType.COMPARE_AND_EXCHANGE), COMPARE_AND_EXCHANGE_RELEASE(TestAccessType.COMPARE_AND_EXCHANGE), WEAK_COMPARE_AND_SET(TestAccessType.COMPARE_AND_SET), + WEAK_COMPARE_AND_SET_VOLATILE(TestAccessType.COMPARE_AND_SET), WEAK_COMPARE_AND_SET_ACQUIRE(TestAccessType.COMPARE_AND_SET), WEAK_COMPARE_AND_SET_RELEASE(TestAccessType.COMPARE_AND_SET), GET_AND_SET(TestAccessType.GET_AND_SET), diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java index b22fc3e182a..021091484e6 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java @@ -104,6 +104,7 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -279,6 +280,10 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, true, false); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, true, false); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, true, false); }); @@ -361,6 +366,10 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(true, false); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(true, false); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(true, false); }); @@ -433,6 +442,10 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, true, false); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, true, false); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, true, false); }); @@ -505,6 +518,10 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(true, false); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(true, false); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(true, false); }); @@ -584,6 +601,10 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, i, true, false); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, i, true, false); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, i, true, false); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java index 088a519e920..e550815156c 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java @@ -104,6 +104,7 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -279,6 +280,10 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, (byte)1, (byte)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, (byte)1, (byte)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, (byte)1, (byte)2); }); @@ -361,6 +366,10 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet((byte)1, (byte)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile((byte)1, (byte)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire((byte)1, (byte)2); }); @@ -433,6 +442,10 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, (byte)1, (byte)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, (byte)1, (byte)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, (byte)1, (byte)2); }); @@ -505,6 +518,10 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet((byte)1, (byte)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile((byte)1, (byte)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire((byte)1, (byte)2); }); @@ -584,6 +601,10 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, i, (byte)1, (byte)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, i, (byte)1, (byte)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, i, (byte)1, (byte)2); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java index 18ff6542615..5c13c6d6677 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java @@ -104,6 +104,7 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -279,6 +280,10 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, 'a', 'b'); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, 'a', 'b'); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, 'a', 'b'); }); @@ -361,6 +366,10 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet('a', 'b'); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile('a', 'b'); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire('a', 'b'); }); @@ -433,6 +442,10 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, 'a', 'b'); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, 'a', 'b'); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, 'a', 'b'); }); @@ -505,6 +518,10 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet('a', 'b'); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile('a', 'b'); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire('a', 'b'); }); @@ -584,6 +601,10 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, i, 'a', 'b'); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, i, 'a', 'b'); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, i, 'a', 'b'); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java index 36c84e2f753..65125e3f62e 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java @@ -104,6 +104,7 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -279,6 +280,10 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, 1.0d, 2.0d); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, 1.0d, 2.0d); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, 1.0d, 2.0d); }); @@ -361,6 +366,10 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(1.0d, 2.0d); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(1.0d, 2.0d); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(1.0d, 2.0d); }); @@ -433,6 +442,10 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, 1.0d, 2.0d); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, 1.0d, 2.0d); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, 1.0d, 2.0d); }); @@ -505,6 +518,10 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(1.0d, 2.0d); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(1.0d, 2.0d); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(1.0d, 2.0d); }); @@ -584,6 +601,10 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, i, 1.0d, 2.0d); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, i, 1.0d, 2.0d); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, i, 1.0d, 2.0d); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java index 2ea2d9617be..8e7491ad45a 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java @@ -104,6 +104,7 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -279,6 +280,10 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, 1.0f, 2.0f); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, 1.0f, 2.0f); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, 1.0f, 2.0f); }); @@ -361,6 +366,10 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(1.0f, 2.0f); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(1.0f, 2.0f); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(1.0f, 2.0f); }); @@ -433,6 +442,10 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, 1.0f, 2.0f); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, 1.0f, 2.0f); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, 1.0f, 2.0f); }); @@ -505,6 +518,10 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(1.0f, 2.0f); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(1.0f, 2.0f); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(1.0f, 2.0f); }); @@ -584,6 +601,10 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, i, 1.0f, 2.0f); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, i, 1.0f, 2.0f); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, i, 1.0f, 2.0f); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java index 0c3d8d5c841..bfcb5feec4c 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java @@ -104,6 +104,7 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -421,12 +422,19 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { assertEquals(x, 2, "weakCompareAndSetRelease int"); } + { + boolean r = vh.weakCompareAndSetVolatile(recv, 2, 1); + assertEquals(r, true, "weakCompareAndSetVolatile int"); + int x = (int) vh.get(recv); + assertEquals(x, 1, "weakCompareAndSetVolatile int value"); + } + // Compare set and get { - int o = (int) vh.getAndSet(recv, 1); - assertEquals(o, 2, "getAndSet int"); + int o = (int) vh.getAndSet(recv, 2); + assertEquals(o, 1, "getAndSet int"); int x = (int) vh.get(recv); - assertEquals(x, 1, "getAndSet int value"); + assertEquals(x, 2, "getAndSet int value"); } vh.set(recv, 1); @@ -549,18 +557,25 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } { - boolean r = (boolean) vh.weakCompareAndSetRelease( 1, 2); + boolean r = (boolean) vh.weakCompareAndSetRelease(1, 2); assertEquals(r, true, "weakCompareAndSetRelease int"); int x = (int) vh.get(); assertEquals(x, 2, "weakCompareAndSetRelease int"); } + { + boolean r = (boolean) vh.weakCompareAndSetVolatile(2, 1); + assertEquals(r, true, "weakCompareAndSetVolatile int"); + int x = (int) vh.get(); + assertEquals(x, 1, "weakCompareAndSetVolatile int value"); + } + // Compare set and get { - int o = (int) vh.getAndSet( 1); - assertEquals(o, 2, "getAndSet int"); + int o = (int) vh.getAndSet( 2); + assertEquals(o, 1, "getAndSet int"); int x = (int) vh.get(); - assertEquals(x, 1, "getAndSet int value"); + assertEquals(x, 2, "getAndSet int value"); } vh.set(1); @@ -692,12 +707,19 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { assertEquals(x, 2, "weakCompareAndSetRelease int"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, 2, 1); + assertEquals(r, true, "weakCompareAndSetVolatile int"); + int x = (int) vh.get(array, i); + assertEquals(x, 1, "weakCompareAndSetVolatile int value"); + } + // Compare set and get { - int o = (int) vh.getAndSet(array, i, 1); - assertEquals(o, 2, "getAndSet int"); + int o = (int) vh.getAndSet(array, i, 2); + assertEquals(o, 1, "getAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, 1, "getAndSet int value"); + assertEquals(x, 2, "getAndSet int value"); } vh.set(array, i, 1); @@ -777,6 +799,10 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, ci, 1, 2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, 1, 2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, 1, 2); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java index a034a536468..1f02bed9045 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java @@ -104,6 +104,7 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -421,12 +422,19 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { assertEquals(x, 2L, "weakCompareAndSetRelease long"); } + { + boolean r = vh.weakCompareAndSetVolatile(recv, 2L, 1L); + assertEquals(r, true, "weakCompareAndSetVolatile long"); + long x = (long) vh.get(recv); + assertEquals(x, 1L, "weakCompareAndSetVolatile long value"); + } + // Compare set and get { - long o = (long) vh.getAndSet(recv, 1L); - assertEquals(o, 2L, "getAndSet long"); + long o = (long) vh.getAndSet(recv, 2L); + assertEquals(o, 1L, "getAndSet long"); long x = (long) vh.get(recv); - assertEquals(x, 1L, "getAndSet long value"); + assertEquals(x, 2L, "getAndSet long value"); } vh.set(recv, 1L); @@ -549,18 +557,25 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } { - boolean r = (boolean) vh.weakCompareAndSetRelease( 1L, 2L); + boolean r = (boolean) vh.weakCompareAndSetRelease(1L, 2L); assertEquals(r, true, "weakCompareAndSetRelease long"); long x = (long) vh.get(); assertEquals(x, 2L, "weakCompareAndSetRelease long"); } + { + boolean r = (boolean) vh.weakCompareAndSetVolatile(2L, 1L); + assertEquals(r, true, "weakCompareAndSetVolatile long"); + long x = (long) vh.get(); + assertEquals(x, 1L, "weakCompareAndSetVolatile long value"); + } + // Compare set and get { - long o = (long) vh.getAndSet( 1L); - assertEquals(o, 2L, "getAndSet long"); + long o = (long) vh.getAndSet( 2L); + assertEquals(o, 1L, "getAndSet long"); long x = (long) vh.get(); - assertEquals(x, 1L, "getAndSet long value"); + assertEquals(x, 2L, "getAndSet long value"); } vh.set(1L); @@ -692,12 +707,19 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { assertEquals(x, 2L, "weakCompareAndSetRelease long"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, 2L, 1L); + assertEquals(r, true, "weakCompareAndSetVolatile long"); + long x = (long) vh.get(array, i); + assertEquals(x, 1L, "weakCompareAndSetVolatile long value"); + } + // Compare set and get { - long o = (long) vh.getAndSet(array, i, 1L); - assertEquals(o, 2L, "getAndSet long"); + long o = (long) vh.getAndSet(array, i, 2L); + assertEquals(o, 1L, "getAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, 1L, "getAndSet long value"); + assertEquals(x, 2L, "getAndSet long value"); } vh.set(array, i, 1L); @@ -777,6 +799,10 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, ci, 1L, 2L); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, 1L, 2L); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, 1L, 2L); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java index 4ff25cc4a5f..822252f7a7d 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java @@ -104,6 +104,7 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -279,6 +280,10 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, (short)1, (short)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, (short)1, (short)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, (short)1, (short)2); }); @@ -361,6 +366,10 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet((short)1, (short)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile((short)1, (short)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire((short)1, (short)2); }); @@ -433,6 +442,10 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, (short)1, (short)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, (short)1, (short)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, (short)1, (short)2); }); @@ -505,6 +518,10 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet((short)1, (short)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile((short)1, (short)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire((short)1, (short)2); }); @@ -584,6 +601,10 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, i, (short)1, (short)2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, i, (short)1, (short)2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, i, (short)1, (short)2); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java index 4272c898a4c..9e4ec77768b 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java @@ -104,6 +104,7 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -435,12 +436,19 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { assertEquals(x, "bar", "weakCompareAndSetRelease String"); } + { + boolean r = vh.weakCompareAndSetVolatile(recv, "bar", "foo"); + assertEquals(r, true, "weakCompareAndSetVolatile String"); + String x = (String) vh.get(recv); + assertEquals(x, "foo", "weakCompareAndSetVolatile String value"); + } + // Compare set and get { - String o = (String) vh.getAndSet(recv, "foo"); - assertEquals(o, "bar", "getAndSet String"); + String o = (String) vh.getAndSet(recv, "bar"); + assertEquals(o, "foo", "getAndSet String"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "getAndSet String value"); + assertEquals(x, "bar", "getAndSet String value"); } } @@ -561,18 +569,25 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } { - boolean r = (boolean) vh.weakCompareAndSetRelease( "foo", "bar"); + boolean r = (boolean) vh.weakCompareAndSetRelease("foo", "bar"); assertEquals(r, true, "weakCompareAndSetRelease String"); String x = (String) vh.get(); assertEquals(x, "bar", "weakCompareAndSetRelease String"); } + { + boolean r = (boolean) vh.weakCompareAndSetVolatile("bar", "foo"); + assertEquals(r, true, "weakCompareAndSetVolatile String"); + String x = (String) vh.get(); + assertEquals(x, "foo", "weakCompareAndSetVolatile String value"); + } + // Compare set and get { - String o = (String) vh.getAndSet( "foo"); - assertEquals(o, "bar", "getAndSet String"); + String o = (String) vh.getAndSet( "bar"); + assertEquals(o, "foo", "getAndSet String"); String x = (String) vh.get(); - assertEquals(x, "foo", "getAndSet String value"); + assertEquals(x, "bar", "getAndSet String value"); } } @@ -702,12 +717,19 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { assertEquals(x, "bar", "weakCompareAndSetRelease String"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, "bar", "foo"); + assertEquals(r, true, "weakCompareAndSetVolatile String"); + String x = (String) vh.get(array, i); + assertEquals(x, "foo", "weakCompareAndSetVolatile String value"); + } + // Compare set and get { - String o = (String) vh.getAndSet(array, i, "foo"); - assertEquals(o, "bar", "getAndSet String"); + String o = (String) vh.getAndSet(array, i, "bar"); + assertEquals(o, "foo", "getAndSet String"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "getAndSet String value"); + assertEquals(x, "bar", "getAndSet String value"); } } @@ -785,6 +807,10 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, ci, "foo", "bar"); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, "foo", "bar"); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, "foo", "bar"); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java index c46720b738a..8159e16ff62 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java @@ -93,6 +93,7 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -203,6 +204,10 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -264,6 +269,10 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -305,6 +314,10 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java index 9cee7930dee..a327b00fb77 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java @@ -93,6 +93,7 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -238,6 +239,10 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkROBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkROBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -333,6 +338,10 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -414,6 +423,10 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -486,6 +499,10 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -561,6 +578,10 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -699,12 +720,19 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease double"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile double"); + double x = (double) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile double value"); + } + // Compare set and get { - double o = (double) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet double"); + double o = (double) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet double value"); + assertEquals(x, VALUE_2, "getAndSet double value"); } } @@ -832,12 +860,19 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease double"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile double"); + double x = (double) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile double value"); + } + // Compare set and get { - double o = (double) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet double"); + double o = (double) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet double value"); + assertEquals(x, VALUE_2, "getAndSet double value"); } } diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java index e366e84c239..196c8101723 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java @@ -93,6 +93,7 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -238,6 +239,10 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkROBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkROBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -333,6 +338,10 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -414,6 +423,10 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -486,6 +499,10 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -561,6 +578,10 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -699,12 +720,19 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease float"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile float"); + float x = (float) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile float value"); + } + // Compare set and get { - float o = (float) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet float"); + float o = (float) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet float value"); + assertEquals(x, VALUE_2, "getAndSet float value"); } } @@ -832,12 +860,19 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease float"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile float"); + float x = (float) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile float value"); + } + // Compare set and get { - float o = (float) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet float"); + float o = (float) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet float value"); + assertEquals(x, VALUE_2, "getAndSet float value"); } } diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java index 2831fa63210..400c20605c5 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java @@ -38,10 +38,10 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; +import java.util.EnumSet; import java.util.List; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.*; public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { static final int SIZE = Integer.BYTES; @@ -93,6 +93,7 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -231,6 +232,10 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkROBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkROBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -319,6 +324,10 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -407,6 +416,10 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -486,6 +499,10 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -568,6 +585,10 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -713,12 +734,19 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease int"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile int"); + int x = (int) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile int value"); + } + // Compare set and get { - int o = (int) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet int"); + int o = (int) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet int value"); + assertEquals(x, VALUE_2, "getAndSet int value"); } vh.set(array, i, VALUE_1); @@ -855,12 +883,19 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease int"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile int"); + int x = (int) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile int value"); + } + // Compare set and get { - int o = (int) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet int"); + int o = (int) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet int value"); + assertEquals(x, VALUE_2, "getAndSet int value"); } vh.set(array, i, VALUE_1); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java index 263245a5e72..a0cabc8653a 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java @@ -93,6 +93,7 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -231,6 +232,10 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkROBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkROBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -319,6 +324,10 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -407,6 +416,10 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -486,6 +499,10 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -568,6 +585,10 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -713,12 +734,19 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease long"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile long"); + long x = (long) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile long value"); + } + // Compare set and get { - long o = (long) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet long"); + long o = (long) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet long value"); + assertEquals(x, VALUE_2, "getAndSet long value"); } vh.set(array, i, VALUE_1); @@ -855,12 +883,19 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease long"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile long"); + long x = (long) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile long value"); + } + // Compare set and get { - long o = (long) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet long"); + long o = (long) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet long value"); + assertEquals(x, VALUE_2, "getAndSet long value"); } vh.set(array, i, VALUE_1); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java index 3d6078e6056..2632b00bd23 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java @@ -93,6 +93,7 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -203,6 +204,10 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -264,6 +269,10 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -305,6 +314,10 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java index 4e8de0c3bc8..8ccf7983056 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java @@ -228,12 +228,19 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { assertEquals(x, 2, "weakCompareAndSetRelease int"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(recv, 2, 1); + assertEquals(r, true, "weakCompareAndSetVolatile int"); + int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(x, 1, "weakCompareAndSetVolatile int value"); + } + // Compare set and get { - int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 1); - assertEquals(o, 2, "getAndSet int"); + int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 2); + assertEquals(o, 1, "getAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1, "getAndSet int value"); + assertEquals(x, 2, "getAndSet int value"); } hs.get(TestAccessMode.SET).invokeExact(recv, 1); @@ -356,18 +363,25 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } { - boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact( 1, 2); + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(1, 2); assertEquals(r, true, "weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, 2, "weakCompareAndSetRelease int"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(2, 1); + assertEquals(r, true, "weakCompareAndSetVolatile int"); + int x = (int) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(x, 1, "weakCompareAndSetVolatile int value"); + } + // Compare set and get { - int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact( 1); - assertEquals(o, 2, "getAndSet int"); + int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(2); + assertEquals(o, 1, "getAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1, "getAndSet int value"); + assertEquals(x, 2, "getAndSet int value"); } hs.get(TestAccessMode.SET).invokeExact(1); @@ -499,12 +513,19 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { assertEquals(x, 2, "weakCompareAndSetRelease int"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(array, i, 2, 1); + assertEquals(r, true, "weakCompareAndSetVolatile int"); + int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(x, 1, "weakCompareAndSetVolatile int value"); + } + // Compare set and get { - int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 1); - assertEquals(o, 2, "getAndSet int"); + int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 2); + assertEquals(o, 1, "getAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1, "getAndSet int value"); + assertEquals(x, 2, "getAndSet int value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, 1); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java index 05efd70079b..65493ec2b49 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java @@ -228,12 +228,19 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { assertEquals(x, 2L, "weakCompareAndSetRelease long"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(recv, 2L, 1L); + assertEquals(r, true, "weakCompareAndSetVolatile long"); + long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(x, 1L, "weakCompareAndSetVolatile long value"); + } + // Compare set and get { - long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 1L); - assertEquals(o, 2L, "getAndSet long"); + long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 2L); + assertEquals(o, 1L, "getAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1L, "getAndSet long value"); + assertEquals(x, 2L, "getAndSet long value"); } hs.get(TestAccessMode.SET).invokeExact(recv, 1L); @@ -356,18 +363,25 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } { - boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact( 1L, 2L); + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(1L, 2L); assertEquals(r, true, "weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, 2L, "weakCompareAndSetRelease long"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(2L, 1L); + assertEquals(r, true, "weakCompareAndSetVolatile long"); + long x = (long) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(x, 1L, "weakCompareAndSetVolatile long value"); + } + // Compare set and get { - long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact( 1L); - assertEquals(o, 2L, "getAndSet long"); + long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(2L); + assertEquals(o, 1L, "getAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1L, "getAndSet long value"); + assertEquals(x, 2L, "getAndSet long value"); } hs.get(TestAccessMode.SET).invokeExact(1L); @@ -499,12 +513,19 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { assertEquals(x, 2L, "weakCompareAndSetRelease long"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(array, i, 2L, 1L); + assertEquals(r, true, "weakCompareAndSetVolatile long"); + long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(x, 1L, "weakCompareAndSetVolatile long value"); + } + // Compare set and get { - long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 1L); - assertEquals(o, 2L, "getAndSet long"); + long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 2L); + assertEquals(o, 1L, "getAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1L, "getAndSet long value"); + assertEquals(x, 2L, "getAndSet long value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, 1L); diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java index 62ef4ae7f37..5ae7c877854 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java @@ -228,12 +228,19 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { assertEquals(x, "bar", "weakCompareAndSetRelease String"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(recv, "bar", "foo"); + assertEquals(r, true, "weakCompareAndSetVolatile String"); + String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(x, "foo", "weakCompareAndSetVolatile String value"); + } + // Compare set and get { - String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, "foo"); - assertEquals(o, "bar", "getAndSet String"); + String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, "bar"); + assertEquals(o, "foo", "getAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "getAndSet String value"); + assertEquals(x, "bar", "getAndSet String value"); } } @@ -352,18 +359,25 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } { - boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact( "foo", "bar"); + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact("foo", "bar"); assertEquals(r, true, "weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, "bar", "weakCompareAndSetRelease String"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact("bar", "foo"); + assertEquals(r, true, "weakCompareAndSetVolatile String"); + String x = (String) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(x, "foo", "weakCompareAndSetVolatile String value"); + } + // Compare set and get { - String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact( "foo"); - assertEquals(o, "bar", "getAndSet String"); + String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact("bar"); + assertEquals(o, "foo", "getAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "getAndSet String value"); + assertEquals(x, "bar", "getAndSet String value"); } } @@ -491,12 +505,19 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { assertEquals(x, "bar", "weakCompareAndSetRelease String"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(array, i, "bar", "foo"); + assertEquals(r, true, "weakCompareAndSetVolatile String"); + String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(x, "foo", "weakCompareAndSetVolatile String value"); + } + // Compare set and get { - String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, "foo"); - assertEquals(o, "bar", "getAndSet String"); + String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, "bar"); + assertEquals(o, "foo", "getAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "getAndSet String value"); + assertEquals(x, "bar", "getAndSet String value"); } } diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java index 0a41906c4a5..13b6b0607b0 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java @@ -374,6 +374,32 @@ public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetVolatile(null, 1, 1); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, 1, 1); + }); + checkWMTE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(recv, Void.class, 1); + }); + checkWMTE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(recv, 1, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetVolatile(0, 1, 1); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(recv, 1, 1, Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkNPE(() -> { // null receiver @@ -972,6 +998,23 @@ public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkWMTE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, 1); + }); + checkWMTE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(1, Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(1, 1, Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkWMTE(() -> { // expected reference class @@ -1566,6 +1609,35 @@ public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetVolatile(null, 0, 1, 1); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, 0, 1, 1); + }); + checkWMTE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(array, 0, Void.class, 1); + }); + checkWMTE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(array, 0, 1, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetVolatile(0, 0, 1, 1); + }); + checkWMTE(() -> { // index reference class + boolean r = vh.weakCompareAndSetVolatile(array, Void.class, 1, 1); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(array, 0, 1, 1, Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkNPE(() -> { // null receiver diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java index f520a619a20..44151683133 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java @@ -374,6 +374,32 @@ public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetVolatile(null, 1L, 1L); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, 1L, 1L); + }); + checkWMTE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(recv, Void.class, 1L); + }); + checkWMTE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(recv, 1L, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetVolatile(0, 1L, 1L); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(recv, 1L, 1L, Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkNPE(() -> { // null receiver @@ -972,6 +998,23 @@ public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkWMTE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, 1L); + }); + checkWMTE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(1L, Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(1L, 1L, Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkWMTE(() -> { // expected reference class @@ -1566,6 +1609,35 @@ public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetVolatile(null, 0, 1L, 1L); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, 0, 1L, 1L); + }); + checkWMTE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(array, 0, Void.class, 1L); + }); + checkWMTE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(array, 0, 1L, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetVolatile(0, 0, 1L, 1L); + }); + checkWMTE(() -> { // index reference class + boolean r = vh.weakCompareAndSetVolatile(array, Void.class, 1L, 1L); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(array, 0, 1L, 1L, Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkNPE(() -> { // null receiver diff --git a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java index 674cc10a236..f3b58c9e2f9 100644 --- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java +++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java @@ -374,6 +374,32 @@ public class VarHandleTestMethodTypeString extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetVolatile(null, "foo", "foo"); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, "foo", "foo"); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(recv, Void.class, "foo"); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(recv, "foo", Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetVolatile(0, "foo", "foo"); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(recv, "foo", "foo", Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkNPE(() -> { // null receiver @@ -878,6 +904,23 @@ public class VarHandleTestMethodTypeString extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, "foo"); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile("foo", Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile("foo", "foo", Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkCCE(() -> { // expected reference class @@ -1407,6 +1450,35 @@ public class VarHandleTestMethodTypeString extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetVolatile(null, 0, "foo", "foo"); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, 0, "foo", "foo"); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(array, 0, Void.class, "foo"); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(array, 0, "foo", Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetVolatile(0, 0, "foo", "foo"); + }); + checkWMTE(() -> { // index reference class + boolean r = vh.weakCompareAndSetVolatile(array, Void.class, "foo", "foo"); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(array, 0, "foo", "foo", Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkNPE(() -> { // null receiver diff --git a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template index fb44c8bbb2b..391dc1a5197 100644 --- a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template +++ b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template @@ -105,6 +105,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -114,6 +115,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -296,6 +298,10 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, $value1$, $value2$); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, $value1$, $value2$); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, $value1$, $value2$); }); @@ -382,6 +388,10 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet($value1$, $value2$); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile($value1$, $value2$); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire($value1$, $value2$); }); @@ -514,12 +524,19 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { assertEquals(x, $value2$, "weakCompareAndSetRelease $type$"); } + { + boolean r = vh.weakCompareAndSetVolatile(recv, $value2$, $value1$); + assertEquals(r, true, "weakCompareAndSetVolatile $type$"); + $type$ x = ($type$) vh.get(recv); + assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value"); + } + // Compare set and get { - $type$ o = ($type$) vh.getAndSet(recv, $value1$); - assertEquals(o, $value2$, "getAndSet $type$"); + $type$ o = ($type$) vh.getAndSet(recv, $value2$); + assertEquals(o, $value1$, "getAndSet $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "getAndSet $type$ value"); + assertEquals(x, $value2$, "getAndSet $type$ value"); } #end[CAS] @@ -558,6 +575,10 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(recv, $value1$, $value2$); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(recv, $value1$, $value2$); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, $value1$, $value2$); }); @@ -684,18 +705,25 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } { - boolean r = (boolean) vh.weakCompareAndSetRelease( $value1$, $value2$); + boolean r = (boolean) vh.weakCompareAndSetRelease($value1$, $value2$); assertEquals(r, true, "weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(); assertEquals(x, $value2$, "weakCompareAndSetRelease $type$"); } + { + boolean r = (boolean) vh.weakCompareAndSetVolatile($value2$, $value1$); + assertEquals(r, true, "weakCompareAndSetVolatile $type$"); + $type$ x = ($type$) vh.get(); + assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value"); + } + // Compare set and get { - $type$ o = ($type$) vh.getAndSet( $value1$); - assertEquals(o, $value2$, "getAndSet $type$"); + $type$ o = ($type$) vh.getAndSet( $value2$); + assertEquals(o, $value1$, "getAndSet $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "getAndSet $type$ value"); + assertEquals(x, $value2$, "getAndSet $type$ value"); } #end[CAS] @@ -734,6 +762,10 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet($value1$, $value2$); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile($value1$, $value2$); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire($value1$, $value2$); }); @@ -869,12 +901,19 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { assertEquals(x, $value2$, "weakCompareAndSetRelease $type$"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, $value2$, $value1$); + assertEquals(r, true, "weakCompareAndSetVolatile $type$"); + $type$ x = ($type$) vh.get(array, i); + assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value"); + } + // Compare set and get { - $type$ o = ($type$) vh.getAndSet(array, i, $value1$); - assertEquals(o, $value2$, "getAndSet $type$"); + $type$ o = ($type$) vh.getAndSet(array, i, $value2$); + assertEquals(o, $value1$, "getAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "getAndSet $type$ value"); + assertEquals(x, $value2$, "getAndSet $type$ value"); } #end[CAS] @@ -917,6 +956,10 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, i, $value1$, $value2$); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, i, $value1$, $value2$); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, i, $value1$, $value2$); }); @@ -996,6 +1039,10 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean r = vh.weakCompareAndSet(array, ci, $value1$, $value2$); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, $value1$, $value2$); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, $value1$, $value2$); }); diff --git a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template index 4cdf45bad80..e433789f8cd 100644 --- a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template +++ b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template @@ -94,6 +94,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -103,6 +104,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); @@ -220,6 +222,10 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -290,6 +296,10 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkROBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkROBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -321,6 +331,10 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -374,6 +388,10 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkUOE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkUOE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -460,6 +478,10 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -552,6 +574,10 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkIOOBE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkIOOBE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -635,6 +661,10 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -721,6 +751,10 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean r = vh.weakCompareAndSet(array, ci, VALUE_1, VALUE_2); }); + checkISE(() -> { + boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2); + }); + checkISE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2); }); @@ -870,12 +904,19 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease $type$"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile $type$"); + $type$ x = ($type$) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile $type$ value"); + } + // Compare set and get { - $type$ o = ($type$) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet $type$"); + $type$ o = ($type$) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet $type$ value"); + assertEquals(x, VALUE_2, "getAndSet $type$ value"); } #end[CAS] @@ -1016,12 +1057,19 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { assertEquals(x, VALUE_2, "weakCompareAndSetRelease $type$"); } + { + boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1); + assertEquals(r, true, "weakCompareAndSetVolatile $type$"); + $type$ x = ($type$) vh.get(array, i); + assertEquals(x, VALUE_1, "weakCompareAndSetVolatile $type$ value"); + } + // Compare set and get { - $type$ o = ($type$) vh.getAndSet(array, i, VALUE_1); - assertEquals(o, VALUE_2, "getAndSet $type$"); + $type$ o = ($type$) vh.getAndSet(array, i, VALUE_2); + assertEquals(o, VALUE_1, "getAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "getAndSet $type$ value"); + assertEquals(x, VALUE_2, "getAndSet $type$ value"); } #end[CAS] diff --git a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template index 8e40761a4f3..f56d9a641a7 100644 --- a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template +++ b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template @@ -229,12 +229,19 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { assertEquals(x, $value2$, "weakCompareAndSetRelease $type$"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(recv, $value2$, $value1$); + assertEquals(r, true, "weakCompareAndSetVolatile $type$"); + $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value"); + } + // Compare set and get { - $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, $value1$); - assertEquals(o, $value2$, "getAndSet $type$"); + $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, $value2$); + assertEquals(o, $value1$, "getAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "getAndSet $type$ value"); + assertEquals(x, $value2$, "getAndSet $type$ value"); } #end[CAS] @@ -387,18 +394,25 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { - boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact( $value1$, $value2$); + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact($value1$, $value2$); assertEquals(r, true, "weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, $value2$, "weakCompareAndSetRelease $type$"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact($value2$, $value1$); + assertEquals(r, true, "weakCompareAndSetVolatile $type$"); + $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value"); + } + // Compare set and get { - $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact( $value1$); - assertEquals(o, $value2$, "getAndSet $type$"); + $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact($value2$); + assertEquals(o, $value1$, "getAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "getAndSet $type$ value"); + assertEquals(x, $value2$, "getAndSet $type$ value"); } #end[CAS] @@ -560,12 +574,19 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { assertEquals(x, $value2$, "weakCompareAndSetRelease $type$"); } + { + boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(array, i, $value2$, $value1$); + assertEquals(r, true, "weakCompareAndSetVolatile $type$"); + $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value"); + } + // Compare set and get { - $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, $value1$); - assertEquals(o, $value2$, "getAndSet $type$"); + $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, $value2$); + assertEquals(o, $value1$, "getAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "getAndSet $type$ value"); + assertEquals(x, $value2$, "getAndSet $type$ value"); } #end[CAS] diff --git a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template index 98e4698c4e4..fe504902f10 100644 --- a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template +++ b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template @@ -375,6 +375,32 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetVolatile(null, $value1$, $value1$); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, $value1$, $value1$); + }); + check{#if[String]?CCE:WMTE}(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(recv, Void.class, $value1$); + }); + check{#if[String]?CCE:WMTE}(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(recv, $value1$, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetVolatile(0, $value1$, $value1$); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(recv, $value1$, $value1$, Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkNPE(() -> { // null receiver @@ -981,6 +1007,23 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + check{#if[String]?CCE:WMTE}(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, $value1$); + }); + check{#if[String]?CCE:WMTE}(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile($value1$, Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile($value1$, $value1$, Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types check{#if[String]?CCE:WMTE}(() -> { // expected reference class @@ -1583,6 +1626,35 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { }); + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetVolatile(null, 0, $value1$, $value1$); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetVolatile(Void.class, 0, $value1$, $value1$); + }); + check{#if[String]?CCE:WMTE}(() -> { // expected reference class + boolean r = vh.weakCompareAndSetVolatile(array, 0, Void.class, $value1$); + }); + check{#if[String]?CCE:WMTE}(() -> { // actual reference class + boolean r = vh.weakCompareAndSetVolatile(array, 0, $value1$, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetVolatile(0, 0, $value1$, $value1$); + }); + checkWMTE(() -> { // index reference class + boolean r = vh.weakCompareAndSetVolatile(array, Void.class, $value1$, $value1$); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetVolatile(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetVolatile(array, 0, $value1$, $value1$, Void.class); + }); + + // WeakCompareAndSetAcquire // Incorrect argument types checkNPE(() -> { // null receiver From 9290ce0c7b17c48c29c2f7e48e6762c0f549d1ce Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Fri, 29 Apr 2016 14:18:09 -0700 Subject: [PATCH 199/222] 8154270: javac wrongly rejects some class literals as annotation element values Reviewed-by: mcimadamore --- .../com/sun/tools/javac/jvm/ClassWriter.java | 2 +- .../EraseClassInfoAnnotationValueTest.java | 57 +++++++++++++++++++ .../javac/annotations/T8154270/Other.java | 29 ++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 langtools/test/tools/javac/annotations/T8154270/EraseClassInfoAnnotationValueTest.java create mode 100644 langtools/test/tools/javac/annotations/T8154270/Other.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java index 3322d0fc5b6..ff02a24d375 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java @@ -826,7 +826,7 @@ public class ClassWriter extends ClassFile { } public void visitClass(Attribute.Class clazz) { databuf.appendByte('c'); - databuf.appendChar(pool.put(typeSig(clazz.classType))); + databuf.appendChar(pool.put(typeSig(types.erasure(clazz.classType)))); } public void visitCompound(Attribute.Compound compound) { databuf.appendByte('@'); diff --git a/langtools/test/tools/javac/annotations/T8154270/EraseClassInfoAnnotationValueTest.java b/langtools/test/tools/javac/annotations/T8154270/EraseClassInfoAnnotationValueTest.java new file mode 100644 index 00000000000..a0843a85a2d --- /dev/null +++ b/langtools/test/tools/javac/annotations/T8154270/EraseClassInfoAnnotationValueTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Google Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; + +/* + * @test + * @bug 8154270 + * @summary javac wrongly rejects some class literals as annotation element values + * @compile EraseClassInfoAnnotationValueTest.java + * @compile -implicit:none Other.java + * @run main EraseClassInfoAnnotationValueTest + */ +public class EraseClassInfoAnnotationValueTest { + + @Retention(RetentionPolicy.RUNTIME) + public @interface A { + Class value(); + } + + static class ParametricType { + + @A(Inner.class) + public static class Nested {} + + public class Inner {} + } + + public static void main(String[] args) { + Class clazz = ParametricType.Nested.class.getAnnotation(A.class).value(); + if (!clazz.equals(ParametricType.Inner.class)) { + throw new AssertionError(clazz); + } + } +} diff --git a/langtools/test/tools/javac/annotations/T8154270/Other.java b/langtools/test/tools/javac/annotations/T8154270/Other.java new file mode 100644 index 00000000000..1238316f3e7 --- /dev/null +++ b/langtools/test/tools/javac/annotations/T8154270/Other.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Google Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Tests separate compilation. + */ +public class Other { + Class clazz = EraseClassInfoAnnotationValueTest.ParametricType.Nested.class; +} From 4be9fb29fa430659302927ee38312d274652b0e5 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Fri, 29 Apr 2016 15:35:51 -0700 Subject: [PATCH 200/222] 8154482: javadoc tool must support legacy doclet and taglet Reviewed-by: jjg --- .../html/resources/standard.properties | 2 +- .../html/resources/standard.properties | 2 +- .../jdk/javadoc/internal/tool/DocEnv.java | 2 +- .../jdk/javadoc/internal/tool/Main.java | 7 - .../jdk/javadoc/internal/tool/Messager.java | 13 +- .../jdk/javadoc/internal/tool/Start.java | 157 +++++-- .../tool/resources/javadoc.properties | 11 +- .../jdk/javadoc/tool/EnsureNewOldDoclet.java | 383 +++++++++++++++--- .../test/tools/lib/toolbox/TestRunner.java | 118 ++++++ 9 files changed, 564 insertions(+), 131 deletions(-) create mode 100644 langtools/test/tools/lib/toolbox/TestRunner.java diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties index 0efe7ee9117..b20f72255fa 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties @@ -1,4 +1,4 @@ -doclet.build_version=Standard Doclet version {0} +doclet.build_version=Standard Doclet (Old) version {0} doclet.Contents=Contents doclet.Overview=Overview doclet.Window_Overview=Overview List diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index 6356cbf3591..6eea5f6e887 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -1,4 +1,4 @@ -doclet.build_version=Standard Doclet (Next) version {0} +doclet.build_version=Standard Doclet version {0} doclet.Contents=Contents doclet.Overview=Overview doclet.Window_Overview=Overview List diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/DocEnv.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/DocEnv.java index 674187dee5d..787a22acbbd 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/DocEnv.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/DocEnv.java @@ -550,7 +550,7 @@ public class DocEnv { // Messager should be replaced by a more general // compilation environment. This can probably // subsume DocEnv as well. - messager.exit(); + throw new Messager.ExitJavadoc(); } /** diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java index 5993176d6f9..a8725f1fb9d 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java @@ -59,13 +59,6 @@ public class Main { * @return The return code. */ public static int execute(String... args) { - // NOTE: the following should be removed when the old doclet - // is removed. - if (args != null && args.length > 0 && "-Xold".equals(args[0])) { - String[] nargs = new String[args.length - 1]; - System.arraycopy(args, 1, nargs, 0, nargs.length); - return com.sun.tools.javadoc.Main.execute(nargs); - } Start jdoc = new Start(); return jdoc.begin(args); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java index bb798f09c9d..d251569532c 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -139,7 +139,7 @@ public class Messager extends Log implements Reporter { } } - public class ExitJavadoc extends Error { + public static class ExitJavadoc extends Error { private static final long serialVersionUID = 0; } @@ -416,15 +416,6 @@ public class Messager extends Log implements Reporter { } } - /** - * Force program exit, e.g., from a fatal error. - *

      - * TODO: This method does not really belong here. - */ - public void exit() { - throw new ExitJavadoc(); - } - private void report(DiagnosticType type, String pos, String msg) { switch (type) { case ERROR: diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java index 824ffc81348..f281ee43a17 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java @@ -66,6 +66,7 @@ import jdk.javadoc.doclet.Doclet.Option; import jdk.javadoc.doclet.DocletEnvironment; import static com.sun.tools.javac.main.Option.*; + /** * Main program of Javadoc. * Previously named "Main". @@ -79,6 +80,12 @@ import static com.sun.tools.javac.main.Option.*; * @author Neal Gafter (rewrite) */ public class Start extends ToolOption.Helper { + + private static final Class OldStdDoclet = + com.sun.tools.doclets.standard.Standard.class; + + private static final Class StdDoclet = + jdk.javadoc.internal.doclets.standard.Standard.class; /** Context for this invocation. */ private final Context context; @@ -193,18 +200,26 @@ public class Start extends ToolOption.Helper { if (foot != null) messager.notice(foot); - if (exit) exit(); + if (exit) + throw new Messager.ExitJavadoc(); } - /** - * Exit - */ - private void exit() { - messager.exit(); - } /** - * Main program - external wrapper + * Main program - external wrapper. In order to maintain backward + * CLI compatibility, we dispatch to the old tool or the old doclet's + * Start mechanism, based on the options present on the command line + * with the following precedence: + * 1. presence of -Xold, dispatch to old tool + * 2. doclet variant, if old, dispatch to old Start + * 3. taglet variant, if old, dispatch to old Start + * + * Thus the presence of -Xold switches the tool, soon after command files + * if any, are expanded, this is performed here, noting that the messager + * is available at this point in time. + * The doclet/taglet tests are performed in the begin method, further on, + * this is to minimize argument processing and most importantly the impact + * of class loader creation, needed to detect the doclet/taglet class variants. */ int begin(String... argv) { // Preprocess @file arguments @@ -212,14 +227,18 @@ public class Start extends ToolOption.Helper { argv = CommandLine.parse(argv); } catch (FileNotFoundException e) { messager.error("main.cant.read", e.getMessage()); - exit(); + throw new Messager.ExitJavadoc(); } catch (IOException e) { e.printStackTrace(System.err); - exit(); + throw new Messager.ExitJavadoc(); } - List argList = Arrays.asList(argv); - boolean ok = begin(argList, Collections. emptySet()); + if (argv.length > 0 && "-Xold".equals(argv[0])) { + messager.warning("main.legacy_api"); + String[] nargv = Arrays.copyOfRange(argv, 1, argv.length); + return com.sun.tools.javadoc.Main.execute(nargv); + } + boolean ok = begin(Arrays.asList(argv), Collections. emptySet()); return ok ? 0 : 1; } @@ -231,11 +250,11 @@ public class Start extends ToolOption.Helper { List opts = new ArrayList<>(); for (String opt: options) opts.add(opt); + return begin(opts, fileObjects); } private boolean begin(List options, Iterable fileObjects) { - fileManager = context.get(JavaFileManager.class); if (fileManager == null) { JavacFileManager.preRegister(context); @@ -244,9 +263,8 @@ public class Start extends ToolOption.Helper { ((BaseFileManager) fileManager).autoClose = true; } } - // locale and doclet needs to be determined first + // locale, doclet and maybe taglet, needs to be determined first docletClass = preProcess(fileManager, options); - if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) { // no need to dispatch to old, safe to init now initMessager(); @@ -257,7 +275,7 @@ public class Start extends ToolOption.Helper { exc.printStackTrace(); if (!apiMode) { error("main.could_not_instantiate_class", docletClass); - messager.exit(); + throw new Messager.ExitJavadoc(); } throw new ClientCodeException(exc); } @@ -267,6 +285,7 @@ public class Start extends ToolOption.Helper { = new com.sun.tools.javadoc.Start(context); return ostart.begin(docletClass, options, fileObjects); } + warn("main.legacy_api"); String[] array = options.toArray(new String[options.size()]); return com.sun.tools.javadoc.Main.execute(array) == 0; } @@ -459,6 +478,11 @@ public class Start extends ToolOption.Helper { String userDocletPath = null; String userDocletName = null; + // taglet specifying arguments, since tagletpath is a doclet + // functionality, assume they are repeated and inspect all. + List userTagletPath = new ArrayList<>(); + List userTagletNames = new ArrayList<>(); + // Step 1: loop through the args, set locale early on, if found. for (int i = 0 ; i < argv.size() ; i++) { String arg = argv.get(i); @@ -470,7 +494,7 @@ public class Start extends ToolOption.Helper { oneArg(argv, i++); if (userDocletName != null) { usageError("main.more_than_one_doclet_specified_0_and_1", - userDocletName, argv.get(i)); + userDocletName, argv.get(i)); } if (docletName != null) { usageError("main.more_than_one_doclet_specified_0_and_1", @@ -484,13 +508,20 @@ public class Start extends ToolOption.Helper { } else { userDocletPath += File.pathSeparator + argv.get(i); } + } else if ("-taglet".equals(arg)) { + userTagletNames.add(argv.get(i + 1)); + } else if ("-tagletpath".equals(arg)) { + for (String pathname : argv.get(i + 1).split(File.pathSeparator)) { + userTagletPath.add(new File(pathname)); + } } } - // Step 2: a doclet has already been provided, - // nothing more to do. + + // Step 2: a doclet is provided, nothing more to do. if (docletClass != null) { return docletClass; } + // Step 3: doclet name specified ? if so find a ClassLoader, // and load it. if (userDocletName != null) { @@ -506,38 +537,80 @@ public class Start extends ToolOption.Helper { try { ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths); } catch (IOException ioe) { - panic("main.doclet_no_classloader_found", ioe); - return null; // keep compiler happy + error("main.doclet_could_not_set_location", paths); + throw new Messager.ExitJavadoc(); } } cl = fileManager.getClassLoader(DOCLET_PATH); if (cl == null) { // despite doclet specified on cmdline no classloader found! - panic("main.doclet_no_classloader_found", userDocletName); - return null; // keep compiler happy - } - try { - Class klass = cl.loadClass(userDocletName); - ensureReadable(klass); - return klass; - } catch (ClassNotFoundException cnfe) { - panic("main.doclet_class_not_found", userDocletName); - return null; // keep compiler happy + error("main.doclet_no_classloader_found", userDocletName); + throw new Messager.ExitJavadoc(); } } + try { + Class klass = cl.loadClass(userDocletName); + ensureReadable(klass); + return klass; + } catch (ClassNotFoundException cnfe) { + error("main.doclet_class_not_found", userDocletName); + throw new Messager.ExitJavadoc(); + } } - // Step 4: we have a doclet, try loading it, otherwise - // return back the standard doclet + + // Step 4: we have a doclet, try loading it if (docletName != null) { try { return Class.forName(docletName, true, getClass().getClassLoader()); } catch (ClassNotFoundException cnfe) { - panic("main.doclet_class_not_found", userDocletName); - return null; // happy compiler, should not happen + error("main.doclet_class_not_found", userDocletName); + throw new Messager.ExitJavadoc(); } - } else { - return jdk.javadoc.internal.doclets.standard.Standard.class; } + + // Step 5: we don't have a doclet specified, do we have taglets ? + if (!userTagletNames.isEmpty() && hasOldTaglet(userTagletNames, userTagletPath)) { + // found a bogey, return the old doclet + return OldStdDoclet; + } + + // finally + return StdDoclet; + } + + /* + * This method returns true iff it finds a legacy taglet, but for + * all other conditions including errors it returns false, allowing + * nature to take its own course. + */ + private boolean hasOldTaglet(List tagletNames, List tagletPaths) { + if (!fileManager.hasLocation(TAGLET_PATH)) { + try { + ((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, tagletPaths); + } catch (IOException ioe) { + error("main.doclet_could_not_set_location", tagletPaths); + throw new Messager.ExitJavadoc(); + } + } + ClassLoader cl = fileManager.getClassLoader(TAGLET_PATH); + if (cl == null) { + // no classloader found! + error("main.doclet_no_classloader_found", tagletNames.get(0)); + throw new Messager.ExitJavadoc(); + } + for (String tagletName : tagletNames) { + try { + Class klass = cl.loadClass(tagletName); + ensureReadable(klass); + if (com.sun.tools.doclets.Taglet.class.isAssignableFrom(klass)) { + return true; + } + } catch (ClassNotFoundException cnfe) { + error("main.doclet_class_not_found", tagletName); + throw new Messager.ExitJavadoc(); + } + } + return false; } private void parseArgs(List args, List javaNames) { @@ -595,16 +668,14 @@ public class Start extends ToolOption.Helper { usage(true); } - // a terminal call, will not return - void panic(String key, Object... args) { - error(key, args); - messager.exit(); - } - void error(String key, Object... args) { messager.error(key, args); } + void warn(String key, Object... args) { + messager.warning(key, args); + } + /** * indicate an option with no arguments was given. */ diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties index f9cab63f716..71fab2bcd31 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties @@ -73,7 +73,8 @@ main.Xusage=\ \ given module. may be ALL-UNNAMED to require\n\ \ the unnamed module.\n\ \ -Xmodule: Specify a module to which the classes being compiled belong.\n\ -\ -Xpatch: Specify location of module class files to patch\n +\ -Xpatch: Specify location of module class files to patch\n\ +\ -Xold Invoke the legacy javadoc tool\n main.Xusage.foot=\ These options are non-standard and subject to change without notice. @@ -96,6 +97,7 @@ For example, on the JDK Classic or HotSpot VMs, add the option -J-Xmx\n\ such as -J-Xmx32m. main.done_in=[done in {0} ms] main.more_than_one_doclet_specified_0_and_1=More than one doclet specified ({0} and {1}). +main.doclet_could_not_set_location=Could not set location for {0} main.doclet_no_classloader_found=Could not obtain classloader to load {0} main.could_not_instantiate_class=Could not instantiate class {0} main.doclet_class_not_found=Cannot find doclet class {0} @@ -109,10 +111,15 @@ main.release.bootclasspath.conflict=option {0} cannot be used together with -rel main.unsupported.release.version=release version {0} not supported main.release.not.standard.file.manager=-release option specified, but the provided JavaFileManager is not a StandardJavaFileManager. main.unknown.error=an unknown error has occurred +main.legacy_api=The old Doclet and Taglet APIs in the packages\n\ + com.sun.javadoc, com.sun.tools.doclets and their implementations\n\ + are planned to be removed in a future JDK release. These\n\ + components have been superseded by the new APIs in jdk.javadoc.doclet.\n\ + Users are strongly recommended to migrate to the new APIs.\n + javadoc.class_not_found=Class {0} not found. javadoc.error=error javadoc.warning=warning - javadoc.error.msg={0}: error - {1} javadoc.warning.msg={0}: warning - {1} javadoc.note.msg = {1} diff --git a/langtools/test/jdk/javadoc/tool/EnsureNewOldDoclet.java b/langtools/test/jdk/javadoc/tool/EnsureNewOldDoclet.java index 9d9547ed65f..6e56617507f 100644 --- a/langtools/test/jdk/javadoc/tool/EnsureNewOldDoclet.java +++ b/langtools/test/jdk/javadoc/tool/EnsureNewOldDoclet.java @@ -23,96 +23,349 @@ /* * @test - * @bug 8035473 - * @summary make sure the new doclet is invoked by default, and -Xold + * @bug 8035473 8154482 + * @summary make sure the javadoc tool responds correctly to Xold, + * old doclets and taglets. + * @library /tools/lib + * @build toolbox.ToolBox toolbox.TestRunner + * @run main EnsureNewOldDoclet */ import java.io.*; -import java.util.ArrayList; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import com.sun.javadoc.Tag; +import com.sun.source.doctree.DocTree; + +import toolbox.*; + /** - * Dummy javadoc comment. + * This test ensures the doclet responds correctly when given + * various conditions that force a fall back to the old javadoc + * tool. The following condition in the order described will + * force a dispatch to the old tool, -Xold, old doclet and old taglet. + * */ -public class EnsureNewOldDoclet { +public class EnsureNewOldDoclet extends TestRunner { - final File javadoc; + final ToolBox tb; final File testSrc; - final String thisClassName; + final Path javadocPath; + final ExecTask task; + final String testClasses; + final PrintStream ostream; - final static Pattern Expected1 = Pattern.compile("^Standard Doclet \\(Next\\) version.*"); - final static Pattern Expected2 = Pattern.compile("^Standard Doclet version.*"); + final static String CLASS_NAME = "EnsureNewOldDoclet"; + final static String OLD_DOCLET_CLASS_NAME = CLASS_NAME + "$OldDoclet"; + final static String NEW_DOCLET_CLASS_NAME = CLASS_NAME + "$NewDoclet"; //unused + final static String OLD_TAGLET_CLASS_NAME = CLASS_NAME + "$OldTaglet"; + final static String NEW_TAGLET_CLASS_NAME = CLASS_NAME + "$NewTaglet"; - public EnsureNewOldDoclet() { - File javaHome = new File(System.getProperty("java.home")); - if (javaHome.getName().endsWith("jre")) - javaHome = javaHome.getParentFile(); - javadoc = new File(new File(javaHome, "bin"), "javadoc"); - testSrc = new File(System.getProperty("test.src")); - thisClassName = EnsureNewOldDoclet.class.getName(); + final static Pattern OLD_HEADER = Pattern.compile("^Standard Doclet \\(Old\\) version.*"); + final static Pattern NEW_HEADER = Pattern.compile("^Standard Doclet version.*"); + + + final static String OLD_DOCLET_MARKER = "OLD_DOCLET_MARKER"; + final static String OLD_TAGLET_MARKER = "Registered: OldTaglet"; + + final static String NEW_DOCLET_MARKER = "NEW_DOCLET_MARKER"; + final static String NEW_TAGLET_MARKER = "Registered Taglet " + CLASS_NAME + "\\$NewTaglet"; + + final static Pattern WARN_TEXT = Pattern.compile("Users are strongly recommended to migrate" + + " to the new APIs."); + final static String OLD_DOCLET_ERROR = "java.lang.NoSuchMethodException: " + + CLASS_NAME +"\\$NewTaglet"; + final static Pattern NEW_DOCLET_ERROR = Pattern.compile(".*java.lang.ClassCastException.*Taglet " + + CLASS_NAME + "\\$OldTaglet.*"); + + final static String OLD_STDDOCLET = "com.sun.tools.doclets.standard.Standard"; + final static String NEW_STDDOCLET = "jdk.javadoc.internal.doclets.standard.Standard"; + + + public EnsureNewOldDoclet() throws Exception { + super(System.err); + ostream = System.err; + testClasses = System.getProperty("test.classes"); + tb = new ToolBox(); + javadocPath = tb.getJDKTool("javadoc"); + task = new ExecTask(tb, javadocPath); + testSrc = new File("Foo.java"); + generateSample(testSrc); + } + + void generateSample(File testSrc) throws Exception { + String nl = System.getProperty("line.separator"); + String src = Arrays.asList( + "/**", + " * A test class to test javadoc. Nothing more nothing less.", + " */", + " public class Foo{}").stream().collect(Collectors.joining(nl)); + tb.writeFile(testSrc.getPath(), src); } public static void main(String... args) throws Exception { - EnsureNewOldDoclet test = new EnsureNewOldDoclet(); - test.run1(); - test.run2(); + new EnsureNewOldDoclet().runTests(); } - // make sure new doclet is invoked by default - void run1() throws Exception { - List output = doTest(javadoc.getPath(), - "-classpath", ".", // insulates us from ambient classpath - "-Xdoclint:none", - "-package", - new File(testSrc, thisClassName + ".java").getPath()); - System.out.println(output); - for (String x : output) { - if (Expected1.matcher(x).matches()) { + // input: nothing, default mode + // outcome: new tool and new doclet + @Test + public void testDefault() throws Exception { + setArgs("-classpath", ".", // insulates us from ambient classpath + testSrc.toString()); + Task.Result tr = task.run(Task.Expect.SUCCESS); + List out = tr.getOutputLines(Task.OutputKind.STDOUT); + checkOutput(testName, out, NEW_HEADER); + } + + // input: -Xold + // outcome: old tool + @Test + public void testXold() throws Exception { + setArgs("-Xold", + "-classpath", ".", // ambient classpath insulation + testSrc.toString()); + Task.Result tr = task.run(Task.Expect.SUCCESS); + List out = tr.getOutputLines(Task.OutputKind.STDOUT); + List err = tr.getOutputLines(Task.OutputKind.STDERR); + checkOutput(testName, out, OLD_HEADER); + checkOutput(testName, err, WARN_TEXT); + } + + // input: old doclet + // outcome: old tool + @Test + public void testOldDoclet() throws Exception { + setArgs("-classpath", ".", // ambient classpath insulation + "-doclet", + OLD_DOCLET_CLASS_NAME, + "-docletpath", + testClasses, + testSrc.toString()); + Task.Result tr = task.run(Task.Expect.SUCCESS); + List out = tr.getOutputLines(Task.OutputKind.STDOUT); + List err = tr.getOutputLines(Task.OutputKind.STDERR); + checkOutput(testName, out, OLD_DOCLET_MARKER); + checkOutput(testName, err, WARN_TEXT); + } + + // input: old taglet + // outcome: old tool + @Test + public void testOldTaglet() throws Exception { + setArgs("-classpath", ".", // ambient classpath insulation + "-taglet", + OLD_TAGLET_CLASS_NAME, + "-tagletpath", + testClasses, + testSrc.toString()); + Task.Result tr = task.run(Task.Expect.SUCCESS); + List out = tr.getOutputLines(Task.OutputKind.STDOUT); + List err = tr.getOutputLines(Task.OutputKind.STDERR); + checkOutput(testName, out, OLD_TAGLET_MARKER); + checkOutput(testName, err, WARN_TEXT); + } + + // input: new doclet and old taglet + // outcome: new doclet with failure + @Test + public void testNewDocletOldTaglet() throws Exception { + setArgs("-classpath", ".", // ambient classpath insulation + "-doclet", + NEW_STDDOCLET, + "-taglet", + OLD_TAGLET_CLASS_NAME, + "-tagletpath", + testClasses, + testSrc.toString()); + Task.Result tr = task.run(Task.Expect.FAIL, 1); + //Task.Result tr = task.run(); + List out = tr.getOutputLines(Task.OutputKind.STDOUT); + List err = tr.getOutputLines(Task.OutputKind.STDERR); + checkOutput(testName, out, NEW_HEADER); + checkOutput(testName, err, NEW_DOCLET_ERROR); + } + + // input: old doclet and old taglet + // outcome: old doclet and old taglet should register + @Test + public void testOldDocletOldTaglet() throws Exception { + setArgs("-classpath", ".", // ambient classpath insulation + "-doclet", + OLD_STDDOCLET, + "-taglet", + OLD_TAGLET_CLASS_NAME, + "-tagletpath", + testClasses, + testSrc.toString()); + Task.Result tr = task.run(Task.Expect.SUCCESS); + List out = tr.getOutputLines(Task.OutputKind.STDOUT); + List err = tr.getOutputLines(Task.OutputKind.STDERR); + checkOutput(testName, out, OLD_HEADER); + checkOutput(testName, out, OLD_TAGLET_MARKER); + checkOutput(testName, err, WARN_TEXT); + } + + // input: new doclet and new taglet + // outcome: new doclet and new taglet should register + @Test + public void testNewDocletNewTaglet() throws Exception { + setArgs("-classpath", ".", // ambient classpath insulation + "-doclet", + NEW_STDDOCLET, + "-taglet", + NEW_TAGLET_CLASS_NAME, + "-tagletpath", + testClasses, + testSrc.toString()); + Task.Result tr = task.run(Task.Expect.SUCCESS); + List out = tr.getOutputLines(Task.OutputKind.STDOUT); + List err = tr.getOutputLines(Task.OutputKind.STDERR); + checkOutput(testName, out, NEW_HEADER); + checkOutput(testName, out, NEW_TAGLET_MARKER); + } + + // input: old doclet and new taglet + // outcome: old doclet and error + @Test + public void testOldDocletNewTaglet() throws Exception { + setArgs("-classpath", ".", // ambient classpath insulation + "-doclet", + OLD_STDDOCLET, + "-taglet", + NEW_TAGLET_CLASS_NAME, + "-tagletpath", + testClasses, + testSrc.toString()); + Task.Result tr = task.run(Task.Expect.FAIL, 1); + List out = tr.getOutputLines(Task.OutputKind.STDOUT); + List err = tr.getOutputLines(Task.OutputKind.STDERR); + checkOutput(testName, out, OLD_HEADER); + checkOutput(testName, err, WARN_TEXT); + checkOutput(testName, err, OLD_DOCLET_ERROR); + } + + void setArgs(String... args) { + ostream.println("cmds: " + Arrays.asList(args)); + task.args(args); + } + + void checkOutput(String testCase, List content, String toFind) throws Exception { + checkOutput(testCase, content, Pattern.compile(".*" + toFind + ".*")); + } + + void checkOutput(String testCase, List content, Pattern toFind) throws Exception { + ostream.println("---" + testCase + "---"); + content.stream().forEach(x -> System.out.println(x)); + for (String x : content) { + ostream.println(x); + if (toFind.matcher(x).matches()) { return; } } - throw new Exception("run1: Expected string not found:"); + throw new Exception(testCase + ": Expected string not found: " + toFind); } - // make sure the old doclet is invoked with -Xold - void run2() throws Exception { - List output = doTest(javadoc.getPath(), - "-Xold", - "-classpath", ".", // insulates us from ambient classpath - "-Xdoclint:none", - "-package", - new File(testSrc, thisClassName + ".java").getPath()); - - for (String x : output) { - if (Expected2.matcher(x).matches()) { - throw new Exception("run2: Expected string not found"); - } - return; + public static class OldDoclet extends com.sun.javadoc.Doclet { + public static boolean start(com.sun.javadoc.RootDoc root) { + System.out.println(OLD_DOCLET_MARKER); + return true; } } - /** - * More dummy comments. - */ - List doTest(String... args) throws Exception { - List output = new ArrayList<>(); - // run javadoc in separate process to ensure doclet executed under - // normal user conditions w.r.t. classloader - Process p = new ProcessBuilder() - .command(args) - .redirectErrorStream(true) - .start(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()))) { - String line = in.readLine(); - while (line != null) { - output.add(line.trim()); - line = in.readLine(); - } + public static class OldTaglet implements com.sun.tools.doclets.Taglet { + + public static void register(Map map) { + EnsureNewOldDoclet.OldTaglet tag = new OldTaglet(); + com.sun.tools.doclets.Taglet t = (com.sun.tools.doclets.Taglet) map.get(tag.getName()); + System.out.println(OLD_TAGLET_MARKER); } - int rc = p.waitFor(); - if (rc != 0) - throw new Exception("javadoc failed, rc:" + rc); - return output; + + @Override + public boolean inField() { + return true; + } + + @Override + public boolean inConstructor() { + return true; + } + + @Override + public boolean inMethod() { + return true; + } + + @Override + public boolean inOverview() { + return true; + } + + @Override + public boolean inPackage() { + return true; + } + + @Override + public boolean inType() { + return true; + } + + @Override + public boolean isInlineTag() { + return true; + } + + @Override + public String getName() { + return "OldTaglet"; + } + + @Override + public String toString(Tag tag) { + return getName(); + } + + @Override + public String toString(Tag[] tags) { + return getName(); + } + } + + public static class NewTaglet implements jdk.javadoc.doclet.taglet.Taglet { + + @Override + public Set getAllowedLocations() { + return Collections.emptySet(); + } + + @Override + public boolean isInlineTag() { + return true; + } + + @Override + public String getName() { + return "NewTaglet"; + } + + @Override + public String toString(DocTree tag) { + return tag.toString(); + } + + @Override + public String toString(List tags) { + return tags.toString(); + } + } } diff --git a/langtools/test/tools/lib/toolbox/TestRunner.java b/langtools/test/tools/lib/toolbox/TestRunner.java new file mode 100644 index 00000000000..22034730405 --- /dev/null +++ b/langtools/test/tools/lib/toolbox/TestRunner.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package toolbox; + +import java.io.PrintStream; +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.function.Function; + +/** + * Utility class to manage and execute sub-tests within a test. + * + * This class does the following: + * i. invokes those test methods annotated with @Test + * ii. keeps track of successful and failed tests + * iii. throws an Exception if any test fails. + * iv. provides a test summary at the end of the run. + * + * Tests must extend this class, annotate the test methods + * with @Test and call one of the runTests method. + */ + +public abstract class TestRunner { + /** Marker annotation for test cases. */ + @Retention(RetentionPolicy.RUNTIME) + public @interface Test { } + + int testCount = 0; + int errorCount = 0; + + public String testName = null; + + final PrintStream out; + + /** + * Constructs the Object. + * @param out the PrintStream to print output to. + */ + public TestRunner(PrintStream out) { + this.out = out; + } + + /** + * Invoke all methods annotated with @Test. + * @throws java.lang.Exception + */ + public void runTests() throws Exception { + runTests(f -> new Object[0]); + } + + /** + * Invoke all methods annotated with @Test. + * @param f a lambda expression to specify arguments. + * @throws java.lang.Exception + */ + public void runTests(Function f) throws Exception { + for (Method m : getClass().getDeclaredMethods()) { + Annotation a = m.getAnnotation(Test.class); + if (a != null) { + testName = m.getName(); + try { + testCount++; + out.println("test: " + testName); + m.invoke(this, f.apply(m)); + } catch (InvocationTargetException e) { + errorCount++; + Throwable cause = e.getCause(); + out.println("Exception: " + e.getCause()); + cause.printStackTrace(out); + } + out.println(); + } + } + + if (testCount == 0) { + throw new Error("no tests found"); + } + + StringBuilder summary = new StringBuilder(); + if (testCount != 1) { + summary.append(testCount).append(" tests"); + } + if (errorCount > 0) { + if (summary.length() > 0) { + summary.append(", "); + } + summary.append(errorCount).append(" errors"); + } + out.println(summary); + if (errorCount > 0) { + throw new Exception(errorCount + " errors found"); + } + } +} From 2006da59300679eb938a5bdb6fd7631d9ef1fbf6 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Fri, 29 Apr 2016 19:53:19 -0700 Subject: [PATCH 201/222] 8139837: JShell API: make a common JShellException Reviewed-by: jlahoda --- .../share/classes/jdk/jshell/Eval.java | 7 ++-- .../classes/jdk/jshell/EvalException.java | 2 +- .../classes/jdk/jshell/ExecutionControl.java | 4 +- .../classes/jdk/jshell/JShellException.java | 37 +++++++++++++++++++ .../classes/jdk/jshell/SnippetEvent.java | 6 +-- .../share/classes/jdk/jshell/Unit.java | 2 +- .../jshell/UnresolvedReferenceException.java | 2 +- 7 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/jshell/JShellException.java diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java index 961eafbf0c0..1d8af24b28c 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java @@ -452,7 +452,7 @@ class Eval { // If appropriate, execute the snippet String value = null; - Exception exception = null; + JShellException exception = null; if (si.status().isDefined) { if (si.isExecutable()) { try { @@ -462,7 +462,8 @@ class Eval { : ""; } catch (EvalException ex) { exception = translateExecutionException(ex); - } catch (UnresolvedReferenceException ex) { + } catch (JShellException ex) { + // UnresolvedReferenceException exception = ex; } } else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) { @@ -499,7 +500,7 @@ class Eval { || e.exception() != null; } - private List events(Unit c, Collection outs, String value, Exception exception) { + private List events(Unit c, Collection outs, String value, JShellException exception) { List events = new ArrayList<>(); events.add(c.event(value, exception)); events.addAll(outs.stream() diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/EvalException.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/EvalException.java index 6c7a5f8fd63..27c351d635f 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/EvalException.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/EvalException.java @@ -40,7 +40,7 @@ package jdk.jshell; * empty string. */ @SuppressWarnings("serial") // serialVersionUID intentionally omitted -public class EvalException extends Exception { +public class EvalException extends JShellException { private final String exceptionClass; EvalException(String message, String exceptionClass, StackTraceElement[] stackElements) { diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java index 40186742741..f28323e178c 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java @@ -119,7 +119,7 @@ class ExecutionControl { } } - String commandInvoke(String classname) throws EvalException, UnresolvedReferenceException { + String commandInvoke(String classname) throws JShellException { try { synchronized (STOP_LOCK) { userCodeRunning = true; @@ -213,7 +213,7 @@ class ExecutionControl { } } - private boolean readAndReportExecutionResult() throws IOException, EvalException, UnresolvedReferenceException { + private boolean readAndReportExecutionResult() throws IOException, JShellException { int ok = in.readInt(); switch (ok) { case RESULT_SUCCESS: diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShellException.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShellException.java new file mode 100644 index 00000000000..721bf1e6c47 --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShellException.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.jshell; + +/** + * The superclass of JShell generated exceptions + */ +@SuppressWarnings("serial") // serialVersionUID intentionally omitted +public class JShellException extends Exception { + + JShellException(String message) { + super(message); + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java index 36446468860..b4d0fb0174f 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java @@ -44,7 +44,7 @@ public class SnippetEvent { SnippetEvent(Snippet snippet, Status previousStatus, Status status, boolean isSignatureChange, Snippet causeSnippet, - String value, Exception exception) { + String value, JShellException exception) { this.snippet = snippet; this.previousStatus = previousStatus; this.status = status; @@ -60,7 +60,7 @@ public class SnippetEvent { private final boolean isSignatureChange; private final Snippet causeSnippet; private final String value; - private final Exception exception; + private final JShellException exception; /** * The Snippet which has changed @@ -121,7 +121,7 @@ public class SnippetEvent { * during execution, otherwise null. * @return the exception or null. */ - public Exception exception() { + public JShellException exception() { return exception; } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java index e5892470440..987dc6bc93e 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java @@ -440,7 +440,7 @@ final class Unit { : msi.parameterTypes(); } - SnippetEvent event(String value, Exception exception) { + SnippetEvent event(String value, JShellException exception) { boolean wasSignatureChanged = sigChanged(); state.debug(DBG_EVNT, "Snippet: %s id: %s before: %s status: %s sig: %b cause: %s\n", si, si.id(), prevStatus, si.status(), wasSignatureChanged, causalSnippet); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java index 3e3de8fd943..be91686eff3 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java @@ -38,7 +38,7 @@ package jdk.jshell; * empty string. */ @SuppressWarnings("serial") // serialVersionUID intentionally omitted -public class UnresolvedReferenceException extends Exception { +public class UnresolvedReferenceException extends JShellException { final DeclarationSnippet snippet; From 6ae0f15a000b2f69686a82d9c7f5c7f7eab9c868 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Fri, 29 Apr 2016 16:06:52 -0700 Subject: [PATCH 202/222] 8155061: javadoc incorrectly sorted items in All Classes list and Index files Reviewed-by: jjg --- .../doclets/toolkit/util/IndexBuilder.java | 6 +- .../internal/doclets/toolkit/util/Utils.java | 61 +++++++++++---- .../doclet/testOrdering/TestOrdering.java | 77 +++++++++++++++---- 3 files changed, 115 insertions(+), 29 deletions(-) diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java index 60090fa0f3a..61051994adc 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java @@ -73,6 +73,7 @@ public class IndexBuilder { private final Configuration configuration; private final Utils utils; + private final Comparator comparator; /** * Constructor. Build the index map. @@ -106,6 +107,9 @@ public class IndexBuilder { this.classesOnly = classesOnly; this.javafx = configuration.javafx; this.indexmap = new TreeMap<>(); + comparator = classesOnly + ? utils.makeAllClassesComparator() + : utils.makeIndexUseComparator(); buildIndexMap(configuration.root); } @@ -175,7 +179,7 @@ public class IndexBuilder { Character.toUpperCase(name.charAt(0)); Character unicode = ch; SortedSet list = indexmap.computeIfAbsent(unicode, - c -> new TreeSet<>(utils.makeIndexUseComparator())); + c -> new TreeSet<>(comparator)); list.add(element); } } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index 1b32bcc6c75..aaa601e839a 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -1628,6 +1628,7 @@ public class Utils { /** * Comparator for ModuleElements, simply compares the fully qualified names + * @return a Comparator */ public Comparator makeModuleComparator() { return new Utils.ElementComparator() { @@ -1639,7 +1640,28 @@ public class Utils { } /** - * Comparator for PackageElements, simply compares the fully qualified names + * Returns a Comparator for all classes, compares the simple names of + * TypeElement, if equal then the fully qualified names. + * + * @return Comparator + */ + public Comparator makeAllClassesComparator() { + return new Utils.ElementComparator() { + @Override + public int compare(Element e1, Element e2) { + int result = compareNames(e1, e2); + if (result == 0) + result = compareFullyQualifiedNames(e1, e2); + + return result; + } + }; + } + + /** + * Returns a Comparator for packages, by comparing the fully qualified names. + * + * @return a Comparator */ public Comparator makePackageComparator() { return new Utils.ElementComparator() { @@ -1650,6 +1672,10 @@ public class Utils { }; } + /** + * Returns a Comparator for SerialFieldTree. + * @return a Comparator + */ public Comparator makeSerialFieldTreeComparator() { return (SerialFieldTree o1, SerialFieldTree o2) -> { String s1 = o1.getName().toString(); @@ -1659,18 +1685,19 @@ public class Utils { } /** - * Comparator for General Purpose - * @return a ElementComparatorForClassUse + * Returns a general purpose comparator. + * @return a Comparator */ public Comparator makeGeneralPurposeComparator() { return makeClassUseComparator(); } /** - * A Comparator for Overrides and Implements use used on ExecutableElements - * compares the name first, then compares the SimpleName of the enclosing - * class and the FullyQualifiedName of the enclosing class. - * @return + * Returns a Comparator for overrides and implements, + * used primarily on methods, compares the name first, + * then compares the simple names of the enclosing + * TypeElement and the fully qualified name of the enclosing TypeElement. + * @return a Comparator */ public Comparator makeOverrideUseComparator() { return new Utils.ElementComparator() { @@ -1696,21 +1723,24 @@ public class Utils { } /** - * A comparator for index file presentations, and are sorted as follows: + * Returns a Comparator for index file presentations, and are sorted as follows. + * If comparing packages then simply compare the qualified names, otherwise * 1. sort on simple names of entities * 2. if equal, then compare the ElementKind ex: Package, Interface etc. * 3a. if equal and if the type is of ExecutableElement(Constructor, Methods), * a case insensitive comparison of parameter the type signatures * 3b. if equal, case sensitive comparison of the type signatures * 4. finally, if equal, compare the FQNs of the entities + * Iff comparing packages then simply sort on qualified names. * @return a comparator for index file use */ public Comparator makeIndexUseComparator() { return new Utils.ElementComparator() { /** - * Compare two given elements, first sort on names, then on the kinds, - * then on the parameters only if the type is an instance of ExecutableElement, - * the parameters are compared and finally the fully qualified names. + * Compare two given elements, if comparing two packages, return the + * comparison of FullyQualifiedName, first sort on names, then on the + * kinds, then on the parameters only if the type is an ExecutableElement, + * the parameters are compared and finally the qualified names. * * @param e1 - an element. * @param e2 - an element. @@ -1719,10 +1749,7 @@ public class Utils { */ @Override public int compare(Element e1, Element e2) { - int result = compareElementTypeKinds(e1, e2); - if (result != 0) { - return result; - } + int result = 0; if (isPackage(e1) && isPackage(e2)) { return compareFullyQualifiedNames(e1, e2); } @@ -1730,6 +1757,10 @@ public class Utils { if (result != 0) { return result; } + result = compareElementTypeKinds(e1, e2); + if (result != 0) { + return result; + } if (hasParameters(e1)) { List parameters1 = ((ExecutableElement)e1).getParameters(); List parameters2 = ((ExecutableElement)e2).getParameters(); diff --git a/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java b/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java index 3e7f7692596..112e6be64ec 100644 --- a/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java +++ b/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8039410 8042601 8042829 8049393 8050031 + * @bug 8039410 8042601 8042829 8049393 8050031 8155061 * @summary test to determine if members are ordered correctly * @author ksrini * @library ../lib/ @@ -72,6 +72,8 @@ public class TestOrdering extends JavadocTester { checkOrder("pkg1/class-use/UsedClass.html", expectedInnerClassContructors); checkOrder("pkg1/ImplementsOrdering.html", expectedImplementsOrdering); checkOrder("pkg1/OverrideOrdering.html", expectedOverrideOrdering); + checkOrder("allclasses-noframe.html", expectedAllClasses); + checkOrder("allclasses-frame.html", expectedAllClasses); } enum ListOrder { NONE, REVERSE, SHUFFLE }; @@ -179,6 +181,22 @@ public class TestOrdering extends JavadocTester { }; String[] composeTestVectors() { List testList = new ArrayList<>(); + + testList.addAll(Arrays.asList(expectedPackageOrdering)); + + for (String x : expectedMethodOrdering) { + testList.add(x); + for (int i = 0; i < MAX_PACKAGES; i++) { + String wpkg = "add" + i; + testList.add(wpkg + "/" + x); + String dpkg = wpkg; + for (int j = 1; j < MAX_SUBPACKAGES_DEPTH; j++) { + dpkg = dpkg + "/" + "add"; + testList.add(dpkg + "/" + x); + } + } + } + for (String x : expectedEnumOrdering) { testList.add(x.replace("REPLACE_ME", "<Unnamed>")); for (int i = 0; i < MAX_PACKAGES; i++) { @@ -194,20 +212,9 @@ public class TestOrdering extends JavadocTester { testList.addAll(Arrays.asList(expectedFieldOrdering)); - for (String x : expectedMethodOrdering) { - testList.add(x); - for (int i = 0; i < MAX_PACKAGES; i++) { - String wpkg = "add" + i; - testList.add(wpkg + "/" + x); - String dpkg = wpkg; - for (int j = 1; j < MAX_SUBPACKAGES_DEPTH; j++) { - dpkg = dpkg + "/" + "add"; - testList.add(dpkg + "/" + x); - } - } - } return testList.toArray(new String[testList.size()]); } + void checkExecutableMemberOrdering(String usePage) { String contents = readFile(usePage); // check constructors @@ -309,6 +316,22 @@ public class TestOrdering extends JavadocTester { return in.replace("/", "."); } + final String expectedAllClasses[] = { + "pkg1/A.html\" title=\"class in pkg1", + "pkg1/A.C.html\" title=\"class in pkg1", + "pkg1/B.html\" title=\"class in pkg1", + "pkg1/B.A.html\" title=\"class in pkg1", + "pkg1/C1.html\" title=\"class in pkg1", + "pkg1/C2.html\" title=\"class in pkg1", + "pkg1/C3.html\" title=\"class in pkg1", + "pkg1/C4.html\" title=\"class in pkg1", + "pkg1/ImplementsOrdering.html\" title=\"interface in pkg1", + "pkg1/MethodOrder.html\" title=\"class in pkg1", + "pkg1/OverrideOrdering.html\" title=\"class in pkg1", + "pkg1/UsedClass.html\" title=\"class in pkg1" + + }; + final String expectedInnerClassContructors[] = { "../../pkg1/A.html#A-pkg1.UsedClass-", "../../pkg1/B.A.html#A-pkg1.UsedClass-", @@ -342,12 +365,33 @@ public class TestOrdering extends JavadocTester { "../../pkg1/MethodOrder.html#m-java.util.Collection-", "../../pkg1/MethodOrder.html#m-java.util.List-" }; + final String expectedClassUseWithTypeParams[] = { "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-", "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-pkg1.UsedClass-", "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-pkg1.UsedClass:A-", "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-java.lang.String-" }; + + final String expectedPackageOrdering[] = { + "\"add0/package-summary.html\">add0 - package add0", + "\"add0/add/package-summary.html\">add0.add - package add0.add", + "\"add0/add/add/package-summary.html\">add0.add.add - package add0.add.add", + "\"add0/add/add/add/package-summary.html\">add0.add.add.add - package add0.add.add.add", + "\"add1/package-summary.html\">add1 - package add1", + "\"add1/add/package-summary.html\">add1.add - package add1.add", + "\"add1/add/add/package-summary.html\">add1.add.add - package add1.add.add", + "\"add1/add/add/add/package-summary.html\">add1.add.add.add - package add1.add.add.add", + "\"add2/package-summary.html\">add2 - package add2", + "\"add2/add/package-summary.html\">add2.add - package add2.add", + "\"add2/add/add/package-summary.html\">add2.add.add - package add2.add.add", + "\"add2/add/add/add/package-summary.html\">add2.add.add.add - package add2.add.add.add", + "\"add3/package-summary.html\">add3 - package add3", + "\"add3/add/package-summary.html\">add3.add - package add3.add", + "\"add3/add/add/package-summary.html\">add3.add.add - package add3.add.add", + "\"add3/add/add/add/package-summary.html\">add3.add.add.add - package add3.add.add.add" + }; + final String expectedMethodOrdering[] = { "Add.html#add--", "Add.html#add-double-", @@ -361,10 +405,12 @@ public class TestOrdering extends JavadocTester { "Add.html#add-java.lang.Double-", "Add.html#add-java.lang.Integer-" }; + final String expectedEnumOrdering[] = { "Add.add.html\" title=\"enum in REPLACE_ME\"", "Add.ADD.html\" title=\"enum in REPLACE_ME\"" }; + final String expectedFieldOrdering[] = { "Add.html#addadd\"", "add0/add/add/add/Add.html#addadd\"", @@ -418,10 +464,12 @@ public class TestOrdering extends JavadocTester { "add3/add/Add.html#ADDADD\"", "add3/Add.html#ADDADD\"" }; + final String expectedPackageTreeOrdering[] = { "", "" }; + final String expectedOverviewOrdering[] = { "", "", @@ -458,6 +506,7 @@ public class TestOrdering extends JavadocTester { "", "", }; + final static String expectedOverviewFrameOrdering[] = { "<unnamed package>", "add0", @@ -477,11 +526,13 @@ public class TestOrdering extends JavadocTester { "add3.add.add", "add3.add.add.add" }; + final static String expectedImplementsOrdering[] = { "

      close in interface java.lang.AutoCloseable
      ", "
      close in interface java.nio.channels.Channel
      ", "
      close in interface java.io.Closeable
      " }; + final static String expectedOverrideOrdering[] = { "
      iterator in interface java.util.Collection<", "
      iterator in interface java.lang.Iterable<" From bab1d3912ac4a3dc6c580530fabc6bb18abd1434 Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Sat, 30 Apr 2016 00:30:31 +0100 Subject: [PATCH 203/222] 8087124: HTTP/2 implementation Reviewed-by: chegar --- .../java/net/http/AsyncConnection.java | 68 ++ .../classes/java/net/http/AsyncEvent.java | 29 +- .../java/net/http/AsyncSSLConnection.java | 129 +++ .../java/net/http/AsyncSSLDelegate.java | 598 +++++++++++++ .../java/net/http/AuthenticationFilter.java | 2 +- .../classes/java/net/http/BufferHandler.java | 16 +- .../java/net/http/ByteBufferConsumer.java | 188 ++++ .../java/net/http/ByteBufferGenerator.java | 136 +++ .../classes/java/net/http/CharsetToolkit.java | 159 ++++ .../classes/java/net/http/ConnectionPool.java | 2 +- .../java/net/http/ContinuationFrame.java | 59 ++ .../classes/java/net/http/CookieFilter.java | 2 +- .../classes/java/net/http/DataFrame.java | 126 +++ .../classes/java/net/http/ErrorFrame.java | 88 ++ .../share/classes/java/net/http/Exchange.java | 51 +- .../classes/java/net/http/FrameReader.java | 70 ++ .../classes/java/net/http/GoAwayFrame.java | 104 +++ .../classes/java/net/http/HeaderFrame.java | 77 ++ .../classes/java/net/http/HeadersFrame.java | 138 +++ .../classes/java/net/http/Http1Exchange.java | 28 +- .../classes/java/net/http/Http1Request.java | 32 +- .../classes/java/net/http/Http1Response.java | 1 - .../java/net/http/Http2ClientImpl.java | 134 ++- .../java/net/http/Http2Connection.java | 781 ++++++++++++++++- .../classes/java/net/http/Http2Frame.java | 211 +++++ .../classes/java/net/http/HttpClientImpl.java | 186 ++-- .../classes/java/net/http/HttpConnection.java | 120 ++- .../java/net/http/HttpHeadersImpl.java | 51 +- .../java/net/http/HttpRequestBuilderImpl.java | 10 +- .../java/net/http/HttpRequestImpl.java | 110 ++- .../classes/java/net/http/HttpResponse.java | 15 +- .../java/net/http/HttpResponseImpl.java | 44 +- .../java/net/http/ImmutableHeaders.java | 79 ++ .../share/classes/java/net/http/Log.java | 60 +- .../classes/java/net/http/MultiExchange.java | 9 +- .../java/net/http/OutgoingHeaders.java | 91 ++ .../share/classes/java/net/http/Pair.java | 5 + .../classes/java/net/http/PingFrame.java | 85 ++ .../java/net/http/PlainHttpConnection.java | 194 ++++- .../net/http/PlainTunnelingConnection.java | 2 +- .../classes/java/net/http/PriorityFrame.java | 82 ++ .../java/net/http/PushPromiseFrame.java | 119 +++ .../share/classes/java/net/http/Queue.java | 143 ++++ .../classes/java/net/http/RawChannel.java | 60 +- .../classes/java/net/http/RedirectFilter.java | 7 +- .../classes/java/net/http/ResetFrame.java | 61 ++ .../java/net/http/ResponseHeaders.java | 6 +- .../classes/java/net/http/SSLConnection.java | 9 +- .../classes/java/net/http/SSLDelegate.java | 35 +- .../java/net/http/SSLTunnelConnection.java | 8 +- .../classes/java/net/http/SettingsFrame.java | 165 ++++ .../share/classes/java/net/http/Stream.java | 805 +++++++++++++++++- .../share/classes/java/net/http/Utils.java | 219 ++++- .../java/net/http/WindowUpdateFrame.java | 78 ++ .../classes/java/net/http/package-info.java | 10 +- jdk/test/java/net/httpclient/APIErrors.java | 47 +- jdk/test/java/net/httpclient/EchoHandler.java | 87 ++ .../net/httpclient/LightWeightHttpServer.java | 8 +- .../java/net/httpclient/ManyRequests.java | 49 +- .../java/net/httpclient/RequestBodyTest.java | 5 +- jdk/test/java/net/httpclient/SmokeTest.java | 22 +- jdk/test/java/net/httpclient/TestKit.java | 101 +++ jdk/test/java/net/httpclient/TestKitTest.java | 130 +++ .../java/net/httpclient/http2/BasicTest.java | 222 +++++ .../java/net/httpclient/http2/ServerPush.java | 107 +++ .../java/net/httpclient/http2/TEST.properties | 1 + .../java/net/http/BodyInputStream.java | 107 +++ .../java/net/http/BodyOutputStream.java | 106 +++ .../java/net/http/EchoHandler.java | 78 ++ .../java/net/http/Http2Handler.java | 18 + .../java/net/http/Http2TestExchange.java | 126 +++ .../java/net/http/Http2TestServer.java | 159 ++++ .../net/http/Http2TestServerConnection.java | 730 ++++++++++++++++ .../java/net/http/OutgoingPushPromise.java | 31 + .../java/net/http/PushHandler.java | 71 ++ .../java/net/http/TestUtil.java | 81 ++ .../java/net/httpclient/security/15.policy | 2 +- 77 files changed, 7799 insertions(+), 586 deletions(-) create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/AsyncConnection.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLConnection.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferConsumer.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferGenerator.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/CharsetToolkit.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/ContinuationFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/DataFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/ErrorFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/FrameReader.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/GoAwayFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/HeaderFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/HeadersFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/Http2Frame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/ImmutableHeaders.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/OutgoingHeaders.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/PingFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/PriorityFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/PushPromiseFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/Queue.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/ResetFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/SettingsFrame.java create mode 100644 jdk/src/java.httpclient/share/classes/java/net/http/WindowUpdateFrame.java create mode 100644 jdk/test/java/net/httpclient/EchoHandler.java create mode 100644 jdk/test/java/net/httpclient/TestKit.java create mode 100644 jdk/test/java/net/httpclient/TestKitTest.java create mode 100644 jdk/test/java/net/httpclient/http2/BasicTest.java create mode 100644 jdk/test/java/net/httpclient/http2/ServerPush.java create mode 100644 jdk/test/java/net/httpclient/http2/TEST.properties create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyInputStream.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyOutputStream.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/EchoHandler.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2Handler.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestExchange.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServer.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServerConnection.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/OutgoingPushPromise.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/PushHandler.java create mode 100644 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/TestUtil.java diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncConnection.java b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncConnection.java new file mode 100644 index 00000000000..8818823af30 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncConnection.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ +package java.net.http; + +import java.nio.ByteBuffer; +import java.util.function.Consumer; + +/** + * Implemented by classes that offer an asynchronous interface. + * + * PlainHttpConnection, AsyncSSLConnection AsyncSSLDelegate. + * + * setAsyncCallbacks() is called to set the callback for reading + * and error notification. Reads all happen on the selector thread, which + * must not block. + * + * Writing uses the same write() methods as used in blocking mode. + * Queues are employed on the writing side to buffer data while it is waiting + * to be sent. This strategy relies on HTTP/2 protocol flow control to stop + * outgoing queue from continually growing. Writes can be initiated by the + * calling thread, but if socket becomes full then the queue is emptied by + * the selector thread + * + */ +interface AsyncConnection { + + /** + * Enables asynchronous sending and receiving mode. The given async + * receiver will receive all incoming data. asyncInput() will be called + * to trigger reads. asyncOutput() will be called to drive writes. + * + * The errorReceiver callback must be called when any fatal exception + * occurs. Connection is assumed to be closed afterwards. + * + * @param asyncReceiver + * @param errorReceiver + */ + void setAsyncCallbacks( + Consumer asyncReceiver, + Consumer errorReceiver); + + /** + * Does whatever is required to start reading. Usually registers + * an event with the selector thread. + */ + void startReading(); +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java index 1cd606fe7a5..b6284398189 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java @@ -25,24 +25,27 @@ package java.net.http; import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; /** * Event handling interface from HttpClientImpl's selector. * - *

      If blockingChannel is true, then the channel will be put in blocking + * If BLOCKING is set, then the channel will be put in blocking * mode prior to handle() being called. If false, then it remains non-blocking. + * + * If REPEATING is set then the event is not cancelled after being posted. */ abstract class AsyncEvent { - /** - * Implement this if channel should be made blocking before calling handle() - */ - public interface Blocking { } + public static final int BLOCKING = 0x1; // non blocking if not set + public static final int REPEATING = 0x2; // one off event if not set - /** - * Implement this if channel should remain non-blocking before calling handle() - */ - public interface NonBlocking { } + protected final int flags; + + AsyncEvent(int flags) { + this.flags = flags; + } /** Returns the channel */ public abstract SelectableChannel channel(); @@ -55,4 +58,12 @@ abstract class AsyncEvent { /** Called when selector is shutting down. Abort all exchanges. */ public abstract void abort(); + + public boolean blocking() { + return (flags & BLOCKING) != 0; + } + + public boolean repeating() { + return (flags & REPEATING) != 0; + } } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLConnection.java b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLConnection.java new file mode 100644 index 00000000000..3dcd2d4933f --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLConnection.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ +package java.net.http; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +/** + * Asynchronous version of SSLConnection. + */ +class AsyncSSLConnection extends HttpConnection implements AsyncConnection { + final AsyncSSLDelegate sslDelegate; + final PlainHttpConnection delegate; + + AsyncSSLConnection(InetSocketAddress addr, HttpClientImpl client, String[] ap) { + super(addr, client); + delegate = new PlainHttpConnection(addr, client); + sslDelegate = new AsyncSSLDelegate(delegate, client, ap); + } + + @Override + public void connect() throws IOException, InterruptedException { + delegate.connect(); + } + + @Override + public CompletableFuture connectAsync() { + return delegate.connectAsync(); + } + + @Override + boolean connected() { + return delegate.connected(); + } + + @Override + boolean isSecure() { + return true; + } + + @Override + boolean isProxied() { + return false; + } + + @Override + SocketChannel channel() { + return delegate.channel(); + } + + @Override + ConnectionPool.CacheKey cacheKey() { + return ConnectionPool.cacheKey(address, null); + } + + @Override + synchronized long write(ByteBuffer[] buffers, int start, int number) throws IOException { + ByteBuffer[] bufs = Utils.reduce(buffers, start, number); + long n = Utils.remaining(bufs); + sslDelegate.write(bufs); + return n; + } + + @Override + long write(ByteBuffer buffer) throws IOException { + long n = buffer.remaining(); + sslDelegate.write(buffer); + return n; + } + + @Override + public void close() { + Utils.close(sslDelegate, delegate.channel()); + } + + @Override + public void setAsyncCallbacks(Consumer asyncReceiver, Consumer errorReceiver) { + sslDelegate.setAsyncCallbacks(asyncReceiver, errorReceiver); + delegate.setAsyncCallbacks(sslDelegate::lowerRead, errorReceiver); + } + + // Blocking read functions not used here + + @Override + protected ByteBuffer readImpl(int length) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + protected int readImpl(ByteBuffer buffer) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + CompletableFuture whenReceivingResponse() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void startReading() { + delegate.startReading(); + sslDelegate.startReading(); + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java new file mode 100644 index 00000000000..217bd7d16ea --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ +package java.net.http; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; +import static javax.net.ssl.SSLEngineResult.Status.*; +import javax.net.ssl.*; +import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*; + +/** + * Asynchronous wrapper around SSLEngine. send and receive is fully non + * blocking. When handshaking is required, a thread is created to perform + * the handshake and application level sends do not take place during this time. + * + * Is implemented using queues and functions operating on the receiving end + * of each queue. + * + * Application writes to: + * || + * \/ + * appOutputQ + * || + * \/ + * appOutputQ read by "upperWrite" method which does SSLEngine.wrap + * and writes to + * || + * \/ + * channelOutputQ + * || + * \/ + * channelOutputQ is read by "lowerWrite" method which is invoked from + * OP_WRITE events on the socket (from selector thread) + * + * Reading side is as follows + * -------------------------- + * + * "upperRead" method reads off channelInputQ and calls SSLEngine.unwrap and + * when decrypted data is returned, it is passed to the user's Consumer + * /\ + * || + * channelInputQ + * /\ + * || + * "lowerRead" method puts buffers into channelInputQ. It is invoked from + * OP_READ events from the selector. + * + * Whenever handshaking is required, the doHandshaking() method is called + * which creates a thread to complete the handshake. It takes over the + * channelInputQ from upperRead, and puts outgoing packets on channelOutputQ. + * Selector events are delivered to lowerRead and lowerWrite as normal. + * + * Errors + * + * Any exception thrown by the engine or channel, causes all Queues to be closed + * the channel to be closed, and the error is reported to the user's + * Consumer + */ +public class AsyncSSLDelegate implements Closeable, AsyncConnection { + + // outgoing buffers put in this queue first and may remain here + // while SSL handshaking happening. + final Queue appOutputQ; + + // queue of wrapped ByteBuffers waiting to be sent on socket channel + //final Queue channelOutputQ; + + // Bytes read into this queue before being unwrapped. Backup on this + // Q should only happen when the engine is stalled due to delegated tasks + final Queue channelInputQ; + + // input occurs through the read() method which is expected to be called + // when the selector signals some data is waiting to be read. All incoming + // handshake data is handled in this method, which means some calls to + // read() may return zero bytes of user data. This is not a sign of spinning, + // just that the handshake mechanics are being executed. + + final SSLEngine engine; + final SSLParameters sslParameters; + //final SocketChannel chan; + final HttpConnection lowerOutput; + final HttpClientImpl client; + final ExecutorService executor; + final BufferHandler bufPool; + Consumer receiver; + Consumer errorHandler; + // Locks. + final Object reader = new Object(); + final Object writer = new Object(); + // synchronizing handshake state + final Object handshaker = new Object(); + // flag set when reader or writer is blocked waiting for handshake to finish + boolean writerBlocked; + boolean readerBlocked; + + // some thread is currently doing the handshake + boolean handshaking; + + // alpn[] may be null. upcall is callback which receives incoming decoded bytes off socket + + AsyncSSLDelegate(HttpConnection lowerOutput, HttpClientImpl client, String[] alpn) + { + SSLContext context = client.sslContext(); + executor = client.executorService(); + bufPool = client; + appOutputQ = new Queue<>(); + appOutputQ.registerPutCallback(this::upperWrite); + //channelOutputQ = new Queue<>(); + //channelOutputQ.registerPutCallback(this::lowerWrite); + engine = context.createSSLEngine(); + engine.setUseClientMode(true); + SSLParameters sslp = client.sslParameters().orElse(null); + if (sslp == null) { + sslp = context.getSupportedSSLParameters(); + //sslp = context.getDefaultSSLParameters(); + //printParams(sslp); + } + sslParameters = Utils.copySSLParameters(sslp); + if (alpn != null) { + sslParameters.setApplicationProtocols(alpn); + Log.logSSL("Setting application protocols: " + Arrays.toString(alpn)); + } else { + Log.logSSL("No application protocols proposed"); + } + engine.setSSLParameters(sslParameters); + engine.setEnabledCipherSuites(sslp.getCipherSuites()); + engine.setEnabledProtocols(sslp.getProtocols()); + this.lowerOutput = lowerOutput; + this.client = client; + this.channelInputQ = new Queue<>(); + this.channelInputQ.registerPutCallback(this::upperRead); + } + + /** + * Put buffers to appOutputQ, and call upperWrite() if q was empty. + * + * @param src + */ + public void write(ByteBuffer[] src) throws IOException { + appOutputQ.putAll(src); + } + + public void write(ByteBuffer buf) throws IOException { + ByteBuffer[] a = new ByteBuffer[1]; + a[0] = buf; + write(a); + } + + @Override + public void close() { + Utils.close(appOutputQ, channelInputQ, lowerOutput); + } + + /** + * Attempts to wrap buffers from appOutputQ and place them on the + * channelOutputQ for writing. If handshaking is happening, then the + * process stalls and last buffers taken off the appOutputQ are put back + * into it until handshaking completes. + * + * This same method is called to try and resume output after a blocking + * handshaking operation has completed. + */ + private void upperWrite() { + try { + EngineResult r = null; + ByteBuffer[] buffers = appOutputQ.pollAll(Utils.EMPTY_BB_ARRAY); + int bytes = Utils.remaining(buffers); + while (bytes > 0) { + synchronized (writer) { + r = wrapBuffers(buffers); + int bytesProduced = r.bytesProduced(); + int bytesConsumed = r.bytesConsumed(); + bytes -= bytesConsumed; + if (bytesProduced > 0) { + // pass destination buffer to channelOutputQ. + lowerOutput.write(r.destBuffer); + } + synchronized (handshaker) { + if (r.handshaking()) { + // handshaking is happening or is needed + // so we put the buffers back on Q to process again + // later. It's possible that some may have already + // been processed, which is ok. + appOutputQ.pushbackAll(buffers); + writerBlocked = true; + if (!handshaking()) { + // execute the handshake in another thread. + // This method will be called again to resume sending + // later + doHandshake(r); + } + return; + } + } + } + } + returnBuffers(buffers); + } catch (Throwable t) { + t.printStackTrace(); + close(); + } + } + + private void doHandshake(EngineResult r) { + handshaking = true; + channelInputQ.registerPutCallback(null); + executor.execute(() -> { + try { + doHandshakeImpl(r); + channelInputQ.registerPutCallback(this::upperRead); + } catch (Throwable t) { + t.printStackTrace(); + close(); + } + }); + } + + private void returnBuffers(ByteBuffer[] bufs) { + for (ByteBuffer buf : bufs) + client.returnBuffer(buf); + } + + /** + * Return true if some thread is currently doing the handshake + * + * @return + */ + boolean handshaking() { + synchronized(handshaker) { + return handshaking; + } + } + + /** + * Executes entire handshake in calling thread. + * Returns after handshake is completed or error occurs + * @param r + * @throws IOException + */ + private void doHandshakeImpl(EngineResult r) throws IOException { + while (true) { + SSLEngineResult.HandshakeStatus status = r.handshakeStatus(); + if (status == NEED_TASK) { + LinkedList tasks = obtainTasks(); + for (Runnable task : tasks) + task.run(); + r = handshakeWrapAndSend(); + } else if (status == NEED_WRAP) { + r = handshakeWrapAndSend(); + } else if (status == NEED_UNWRAP) { + r = handshakeReceiveAndUnWrap(); + } + if (!r.handshaking()) + break; + } + boolean dowrite = false; + boolean doread = false; + // Handshake is finished. Now resume reading and/or writing + synchronized(handshaker) { + handshaking = false; + if (writerBlocked) { + writerBlocked = false; + dowrite = true; + } + if (readerBlocked) { + readerBlocked = false; + doread = true; + } + } + if (dowrite) + upperWrite(); + if (doread) + upperRead(); + } + + // acknowledge a received CLOSE request from peer + void doClosure() throws IOException { + //while (!wrapAndSend(emptyArray)) + //; + } + + LinkedList obtainTasks() { + LinkedList l = new LinkedList<>(); + Runnable r; + while ((r = engine.getDelegatedTask()) != null) + l.add(r); + return l; + } + + @Override + public synchronized void setAsyncCallbacks(Consumer asyncReceiver, Consumer errorReceiver) { + this.receiver = asyncReceiver; + this.errorHandler = errorReceiver; + } + + @Override + public void startReading() { + // maybe this class does not need to implement AsyncConnection + } + + static class EngineResult { + ByteBuffer destBuffer; + ByteBuffer srcBuffer; + SSLEngineResult result; + Throwable t; + + boolean handshaking() { + SSLEngineResult.HandshakeStatus s = result.getHandshakeStatus(); + return s != FINISHED && s != NOT_HANDSHAKING; + } + + int bytesConsumed() { + return result.bytesConsumed(); + } + + int bytesProduced() { + return result.bytesProduced(); + } + + Throwable exception() { + return t; + } + + SSLEngineResult.HandshakeStatus handshakeStatus() { + return result.getHandshakeStatus(); + } + + SSLEngineResult.Status status() { + return result.getStatus(); + } + } + + EngineResult handshakeWrapAndSend() throws IOException { + EngineResult r = wrapBuffer(Utils.EMPTY_BYTEBUFFER); + if (r.bytesProduced() > 0) { + lowerOutput.write(r.destBuffer); + } + return r; + } + + // called during handshaking. It blocks until a complete packet + // is available, unwraps it and returns. + EngineResult handshakeReceiveAndUnWrap() throws IOException { + ByteBuffer buf = channelInputQ.take(); + while (true) { + // block waiting for input + EngineResult r = unwrapBuffer(buf); + SSLEngineResult.Status status = r.status(); + if (status == BUFFER_UNDERFLOW) { + // wait for another buffer to arrive + ByteBuffer buf1 = channelInputQ.take(); + buf = combine (buf, buf1); + continue; + } + // OK + // theoretically possible we could receive some user data + if (r.bytesProduced() > 0) { + receiver.accept(r.destBuffer); + } + if (!buf.hasRemaining()) + return r; + } + } + + EngineResult wrapBuffer(ByteBuffer src) throws SSLException { + ByteBuffer[] bufs = new ByteBuffer[1]; + bufs[0] = src; + return wrapBuffers(bufs); + } + + EngineResult wrapBuffers(ByteBuffer[] src) throws SSLException { + EngineResult r = new EngineResult(); + ByteBuffer dst = bufPool.getBuffer(); + while (true) { + r.result = engine.wrap(src, dst); + switch (r.result.getStatus()) { + case BUFFER_OVERFLOW: + dst = getPacketBuffer(); + break; + case CLOSED: + case OK: + dst.flip(); + r.destBuffer = dst; + return r; + case BUFFER_UNDERFLOW: + // underflow handled externally + bufPool.returnBuffer(dst); + return r; + default: + assert false; + } + } + } + + EngineResult unwrapBuffer(ByteBuffer srcbuf) throws IOException { + EngineResult r = new EngineResult(); + r.srcBuffer = srcbuf; + + ByteBuffer dst = bufPool.getBuffer(); + while (true) { + r.result = engine.unwrap(srcbuf, dst); + switch (r.result.getStatus()) { + case BUFFER_OVERFLOW: + // dest buffer not big enough. Reallocate + int oldcap = dst.capacity(); + dst = getApplicationBuffer(); + assert dst.capacity() > oldcap; + break; + case CLOSED: + doClosure(); + throw new IOException("Engine closed"); + case BUFFER_UNDERFLOW: + bufPool.returnBuffer(dst); + return r; + case OK: + dst.flip(); + r.destBuffer = dst; + return r; + } + } + } + + /** + * Asynchronous read input. Call this when selector fires. + * Unwrap done in upperRead because it also happens in + * doHandshake() when handshake taking place + */ + public void lowerRead(ByteBuffer buffer) { + try { + channelInputQ.put(buffer); + } catch (Throwable t) { + close(); + errorHandler.accept(t); + } + } + + public void upperRead() { + EngineResult r; + ByteBuffer srcbuf; + synchronized (reader) { + try { + srcbuf = channelInputQ.poll(); + if (srcbuf == null) { + return; + } + while (true) { + r = unwrapBuffer(srcbuf); + switch (r.result.getStatus()) { + case BUFFER_UNDERFLOW: + // Buffer too small. Need to combine with next buf + ByteBuffer nextBuf = channelInputQ.poll(); + if (nextBuf == null) { + // no data available. push buffer back until more data available + channelInputQ.pushback(srcbuf); + return; + } else { + srcbuf = combine(srcbuf, nextBuf); + } + break; + case OK: + // check for any handshaking work + synchronized (handshaker) { + if (r.handshaking()) { + // handshaking is happening or is needed + // so we put the buffer back on Q to process again + // later. + channelInputQ.pushback(srcbuf); + readerBlocked = true; + if (!handshaking()) { + // execute the handshake in another thread. + // This method will be called again to resume sending + // later + doHandshake(r); + } + return; + } + } + ByteBuffer dst = r.destBuffer; + if (dst.hasRemaining()) { + receiver.accept(dst); + } + } + if (srcbuf.hasRemaining()) { + continue; + } + srcbuf = channelInputQ.poll(); + if (srcbuf == null) { + return; + } + } + } catch (Throwable t) { + Utils.close(lowerOutput); + errorHandler.accept(t); + } + } + } + + /** + * Get a new buffer that is the right size for application buffers. + * + * @return + */ + ByteBuffer getApplicationBuffer() { + SSLSession session = engine.getSession(); + int appBufsize = session.getApplicationBufferSize(); + bufPool.setMinBufferSize(appBufsize); + return bufPool.getBuffer(appBufsize); + } + + ByteBuffer getPacketBuffer() { + SSLSession session = engine.getSession(); + int packetBufSize = session.getPacketBufferSize(); + bufPool.setMinBufferSize(packetBufSize); + return bufPool.getBuffer(packetBufSize); + } + + ByteBuffer combine(ByteBuffer buf1, ByteBuffer buf2) { + int avail1 = buf1.capacity() - buf1.remaining(); + if (buf2.remaining() < avail1) { + buf1.compact(); + buf1.put(buf2); + buf1.flip(); + return buf1; + } + int newsize = buf1.remaining() + buf2.remaining(); + ByteBuffer newbuf = bufPool.getBuffer(newsize); + newbuf.put(buf1); + newbuf.put(buf2); + newbuf.flip(); + return newbuf; + } + + SSLParameters getSSLParameters() { + return sslParameters; + } + + static void printParams(SSLParameters p) { + System.out.println("SSLParameters:"); + if (p == null) { + System.out.println("Null params"); + return; + } + for (String cipher : p.getCipherSuites()) { + System.out.printf("cipher: %s\n", cipher); + } + for (String approto : p.getApplicationProtocols()) { + System.out.printf("application protocol: %s\n", approto); + } + for (String protocol : p.getProtocols()) { + System.out.printf("protocol: %s\n", protocol); + } + if (p.getServerNames() != null) + for (SNIServerName sname : p.getServerNames()) { + System.out.printf("server name: %s\n", sname.toString()); + } + } + + String getSessionInfo() { + StringBuilder sb = new StringBuilder(); + String application = engine.getApplicationProtocol(); + SSLSession sess = engine.getSession(); + String cipher = sess.getCipherSuite(); + String protocol = sess.getProtocol(); + sb.append("Handshake complete alpn: ") + .append(application) + .append(", Cipher: ") + .append(cipher) + .append(", Protocol: ") + .append(protocol); + return sb.toString(); + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java b/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java index c06f3886a85..2f1a65cc73f 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java @@ -45,7 +45,7 @@ class AuthenticationFilter implements HeaderFilter { static final int DEFAULT_RETRY_LIMIT = 3; static final int retry_limit = Utils.getIntegerNetProperty( - "sun.net.httpclient.auth.retrylimit", DEFAULT_RETRY_LIMIT); + "java.net.httpclient.auth.retrylimit", DEFAULT_RETRY_LIMIT); static final int UNAUTHORIZED = 401; static final int PROXY_UNAUTHORIZED = 407; diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java b/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java index a311422a782..eb25e98e9d1 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java @@ -27,11 +27,23 @@ package java.net.http; import java.nio.ByteBuffer; /** - * Implemented by buffer pools. + * Implemented by buffer pools. A buffer pool has a current buffer size + * (number of bytes in each buffer) which may increase over time. */ interface BufferHandler { - ByteBuffer getBuffer(); + default ByteBuffer getBuffer() { + return getBuffer(-1); + } + + void setMinBufferSize(int size); + + /** + * size == -1 means return any sized buffer. Any other value means + * @param size + * @return + */ + ByteBuffer getBuffer(int size); void returnBuffer(ByteBuffer buffer); } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferConsumer.java b/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferConsumer.java new file mode 100644 index 00000000000..5a37af38b87 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferConsumer.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.function.Supplier; + +/** + * Takes a List which is assumed to contain at least one HTTP/2 + * frame and allows it to be processed supplying bytes, ints, shorts, byte[] etc. + * from the list. As each ByteBuffer is consumed it is removed from the List<>. + * + * NOTE. shorts and bytes returned are UNSIGNED ints + * + * When finished processing the frame, the List may be empty or may contain + * partially read or unread ByteBuffers. A new ByteBufferConsumer can be + * created with the List<> + */ +class ByteBufferConsumer { + + ByteBuffer currentBuffer; + + final List buffers; + final ListIterator iterator; + final Supplier newBufferSupplier; + + ByteBufferConsumer(List buffers, + Supplier newBufferSupplier) { + this.buffers = buffers; + this.newBufferSupplier = newBufferSupplier; + this.iterator = buffers.listIterator(); + if (!iterator.hasNext()) { + throw new IllegalArgumentException("Empty buffer list"); + } + currentBuffer = iterator.next(); + } + + private void dump() { + int l = 0; + System.err.printf("ByteBufferConsumer:\n"); + for (ByteBuffer buf : buffers) { + System.err.printf("\t%s\n", buf.toString()); + l+= buf.remaining(); + } + System.err.printf("BBC contains %d bytes\n", l); + } + + private synchronized ByteBuffer getBuffer(boolean exception) throws IOException { + while (currentBuffer == null || !currentBuffer.hasRemaining()) { + if (currentBuffer != null) { + iterator.remove(); + } + if (!iterator.hasNext()) { + currentBuffer = null; + if (exception) { + throw new IOException ("Connection closed unexpectedly"); + } + return null; + } + currentBuffer = iterator.next(); + } + return currentBuffer; + } + + // call this to check if the data has all been consumed + + public boolean consumed() { + try { + return getBuffer(false) == null; + } catch (IOException e) { + /* CAN'T HAPPEN */ + throw new InternalError(); + } + } + + public int getByte() throws IOException { + // TODO: what to do if connection is closed. Throw NPE? + ByteBuffer buf = getBuffer(true); + return buf.get() & 0xff; + } + + public byte[] getBytes(int n) throws IOException { + return getBytes(n, null); + } + + public byte[] getBytes(int n, byte[] buf) throws IOException { + if (buf == null) { + buf = new byte[n]; + } else if (buf.length < n) { + throw new IllegalArgumentException("getBytes: buffer too small"); + } + int offset = 0; + while (n > 0) { + ByteBuffer b = getBuffer(true); + int length = Math.min(n, b.remaining()); + b.get(buf, offset, length); + offset += length; + n -= length; + } + return buf; + } + + public int getShort() throws IOException { + ByteBuffer buf = getBuffer(true); + int rem = buf.remaining(); + if (rem >= 2) { + return buf.getShort() & 0xffff; + } + // Slow path. Not common + int val = 0; + val = (val << 8) + getByte(); + val = (val << 8) + getByte(); + return val; + } + + public int getInt() throws IOException { + ByteBuffer buf = getBuffer(true); + int rem = buf.remaining(); + if (rem >= 4) { + return buf.getInt(); + } + // Slow path. Not common + int val = 0; + for (int nbytes = 0; nbytes < 4; nbytes++) { + val = (val << 8) + getByte(); + } + return val; + } + + private static final ByteBuffer[] EMPTY = new ByteBuffer[0]; + + /** + * Extracts whatever number of ByteBuffers from list to get required number + * of bytes. Any remaining buffers are 'tidied up' so reading can continue. + */ + public ByteBuffer[] getBuffers(int bytecount) throws IOException { + LinkedList l = new LinkedList<>(); + while (bytecount > 0) { + ByteBuffer buffer = getBuffer(true); + int remaining = buffer.remaining(); + if (remaining > bytecount) { + int difference = remaining - bytecount; + // split + ByteBuffer newb = newBufferSupplier.get(); + newb.clear(); + int limit = buffer.limit(); + buffer.limit(limit - difference); + newb.put(buffer); + newb.flip(); + buffer.limit(limit); + l.add(newb); + bytecount = 0; + } else { + l.add(buffer); + currentBuffer = null; + iterator.remove(); + bytecount -= remaining; + } + } + return l.toArray(EMPTY); + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferGenerator.java b/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferGenerator.java new file mode 100644 index 00000000000..601c4a526b5 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferGenerator.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.nio.ByteBuffer; +import java.util.ArrayList; + +/** + * Manages a ByteBuffer[] for writing frames into for output. The last + * ByteBuffer in the list is always unflipped (able to receive more bytes for + * sending) until getBufferArray() is called, which calls finish(). + * + * This allows multiple frames to be written to the same BBG. + * + * Buffers added with addByteBuffer() must be already flipped. + */ +class ByteBufferGenerator { + + ByteBuffer currentBuffer; + // source is assumed to always return the same sized buffer + final BufferHandler pool; + final ArrayList buflist; + final int bufsize; + boolean finished; + + ByteBufferGenerator(BufferHandler pool) { + this.buflist = new ArrayList<>(); + this.pool = pool; + this.currentBuffer = pool.getBuffer(); + this.bufsize = currentBuffer.capacity(); + } + + private static final ByteBuffer[] EMPTY = new ByteBuffer[0]; + + public ByteBuffer[] getBufferArray() { + finish(); + return buflist.toArray(EMPTY); + } + + public ArrayList getBufferList() { + finish(); + return buflist; + } + + private synchronized void finish() { + if (finished) { + return; + } + finished = true; + currentBuffer.flip(); + if (currentBuffer.hasRemaining()) { + buflist.add(currentBuffer); + } else { + pool.returnBuffer(currentBuffer); + } + } + + // only used for SettingsFrame: offset is number of bytes to + // ignore at start (we only want the payload of the settings frame) + public byte[] asByteArray(int offset) { + ByteBuffer[] bufs = getBufferArray(); + int size = 0; + for (ByteBuffer buf : bufs) { + size += buf.remaining(); + } + byte[] bytes = new byte[size-offset]; + int pos = 0; + for (ByteBuffer buf : bufs) { + int rem = buf.remaining(); + int ignore = Math.min(rem, offset); + buf.position(buf.position()+ignore); + rem -= ignore; + offset -= ignore; + buf.get(bytes, pos, rem); + pos += rem; + } + return bytes; + } + + ByteBuffer getBuffer(long n) { + if (currentBuffer.remaining() < n) { + getNewBuffer(); + if (n > currentBuffer.capacity()) { + throw new IllegalArgumentException("requested buffer too large"); + } + } + return currentBuffer; + } + + void getNewBuffer() { + currentBuffer.flip(); + if (currentBuffer.hasRemaining()) { + buflist.add(currentBuffer); + } else { + pool.returnBuffer(currentBuffer); + } + currentBuffer = pool.getBuffer(); + } + + void addByteBuffer(ByteBuffer buf) { + getNewBuffer(); + buflist.add(buf); + } + + void addPadding(int length) { + while (length > 0) { + int n = Math.min(length, bufsize); + ByteBuffer b = getBuffer(n); + // TODO: currently zeroed? + b.position(b.position() + n); + length -= n; + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/CharsetToolkit.java b/jdk/src/java.httpclient/share/classes/java/net/http/CharsetToolkit.java new file mode 100644 index 00000000000..1264fda0a7b --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/CharsetToolkit.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ +package java.net.http; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +import static java.nio.charset.StandardCharsets.UTF_8; + +// The purpose of this class is to separate charset-related tasks from the main +// WebSocket logic, simplifying where possible. +// +// * Coders hide the differences between coding and flushing stages on the +// API level +// * Verifier abstracts the way the verification is performed +// (spoiler: it's a decoding into a throw-away buffer) +// +// Coding methods throw exceptions instead of returning coding result denoting +// errors, since any kind of handling and recovery is not expected. +final class CharsetToolkit { + + private CharsetToolkit() { } + + static final class Verifier { + + private final CharsetDecoder decoder = UTF_8.newDecoder(); + // A buffer used to check validity of UTF-8 byte stream by decoding it. + // The contents of this buffer are never used. + // The size is arbitrary, though it should probably be chosen from the + // performance perspective since it affects the total number of calls to + // decoder.decode() and amount of work in each of these calls + private final CharBuffer blackHole = CharBuffer.allocate(1024); + + void verify(ByteBuffer in, boolean endOfInput) + throws CharacterCodingException { + while (true) { + // Since decoder.flush() cannot produce an error, it's not + // helpful for verification. Therefore this step is skipped. + CoderResult r = decoder.decode(in, blackHole, endOfInput); + if (r.isOverflow()) { + blackHole.clear(); + } else if (r.isUnderflow()) { + break; + } else if (r.isError()) { + r.throwException(); + } else { + // Should not happen + throw new InternalError(); + } + } + } + + Verifier reset() { + decoder.reset(); + return this; + } + } + + static final class Encoder { + + private final CharsetEncoder encoder = UTF_8.newEncoder(); + private boolean coding = true; + + CoderResult encode(CharBuffer in, ByteBuffer out, boolean endOfInput) + throws CharacterCodingException { + + if (coding) { + CoderResult r = encoder.encode(in, out, endOfInput); + if (r.isOverflow()) { + return r; + } else if (r.isUnderflow()) { + if (endOfInput) { + coding = false; + } else { + return r; + } + } else if (r.isError()) { + r.throwException(); + } else { + // Should not happen + throw new InternalError(); + } + } + assert !coding; + return encoder.flush(out); + } + + Encoder reset() { + coding = true; + encoder.reset(); + return this; + } + } + + static CharBuffer decode(ByteBuffer in) throws CharacterCodingException { + return UTF_8.newDecoder().decode(in); + } + + static final class Decoder { + + private final CharsetDecoder decoder = UTF_8.newDecoder(); + private boolean coding = true; // Either coding or flushing + + CoderResult decode(ByteBuffer in, CharBuffer out, boolean endOfInput) + throws CharacterCodingException { + + if (coding) { + CoderResult r = decoder.decode(in, out, endOfInput); + if (r.isOverflow()) { + return r; + } else if (r.isUnderflow()) { + if (endOfInput) { + coding = false; + } else { + return r; + } + } else if (r.isError()) { + r.throwException(); + } else { + // Should not happen + throw new InternalError(); + } + } + assert !coding; + return decoder.flush(out); + } + + Decoder reset() { + coding = true; + decoder.reset(); + return this; + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java b/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java index 70e475ec6e3..fa32ff30adc 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java @@ -35,7 +35,7 @@ import java.util.Objects; class ConnectionPool { static final long KEEP_ALIVE = Utils.getIntegerNetProperty( - "sun.net.httpclient.keepalive.timeout", 1200); // seconds + "java.net.httpclient.keepalive.timeout", 1200); // seconds // Pools of idle connections diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/ContinuationFrame.java b/jdk/src/java.httpclient/share/classes/java/net/http/ContinuationFrame.java new file mode 100644 index 00000000000..4981df21ca6 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/ContinuationFrame.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; + +class ContinuationFrame extends HeaderFrame { + + public static final int TYPE = 0x9; + + ContinuationFrame() { + type = TYPE; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + headerBlocks = bc.getBuffers(length); + } + + @Override + void writeOutgoing(ByteBufferGenerator bg) { + super.writeOutgoing(bg); + for (int i=0; i> userheaders, cookies; - userheaders = r.getUserHeaders().directMap(); + userheaders = r.getUserHeaders().map(); cookies = cookieMan.get(r.uri(), userheaders); // add the returned cookies HttpHeadersImpl systemHeaders = r.getSystemHeaders(); diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/DataFrame.java b/jdk/src/java.httpclient/share/classes/java/net/http/DataFrame.java new file mode 100644 index 00000000000..d82c7e11623 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/DataFrame.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; +import java.nio.ByteBuffer; + +class DataFrame extends Http2Frame { + + public final static int TYPE = 0x0; + + DataFrame() { + type = TYPE; + } + + // Flags + public static final int END_STREAM = 0x1; + public static final int PADDED = 0x8; + + int padLength; + int dataLength; + ByteBuffer[] data; + + public void setData(ByteBuffer[] data) { + this.data = data; + setDataLength(); + } + + @Override + String flagAsString(int flag) { + switch (flag) { + case END_STREAM: + return "END_STREAM"; + case PADDED: + return "PADDED"; + } + return super.flagAsString(flag); + } + + public synchronized void setData(ByteBuffer data) { + ByteBuffer[] bb; + if (data == null) { + bb = new ByteBuffer[0]; + } else { + bb = new ByteBuffer[1]; + bb[0] = data; + } + setData(bb); + } + + public synchronized ByteBuffer[] getData() { + return data; + } + + private void setDataLength() { + int len = 0; + for (ByteBuffer buf : data) { + len += buf.remaining(); + } + dataLength = len; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + if ((flags & PADDED) != 0) { + padLength = bc.getByte(); + dataLength = length - (padLength + 1); + } else { + dataLength = length; + } + data = bc.getBuffers(dataLength); + } + + int getPadLength() { + return padLength; + } + + int getDataLength() { + return dataLength; + } + + @Override + void writeOutgoing(ByteBufferGenerator bg) { + super.writeOutgoing(bg); + if ((flags & PADDED) != 0) { + ByteBuffer buf = bg.getBuffer(1); + buf.put((byte)getPadLength()); + } + for (int i=0; i LAST_ERROR) { + return "Error: " + Integer.toString(code); + } else { + return errorStrings[code]; + } + } + + int errorCode; + + @Override + public String toString() { + return super.toString() + " Error: " + stringForCode(errorCode); + } + + public int getErrorCode() { + return this.errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java b/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java index 9201d22160a..6d00bc2b215 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java @@ -128,7 +128,7 @@ class Exchange { } } - HttpResponseImpl responseImpl0(HttpConnection connection) + private HttpResponseImpl responseImpl0(HttpConnection connection) throws IOException, InterruptedException { exchImpl = ExchangeImpl.get(this, connection); @@ -136,7 +136,7 @@ class Exchange { request.addSystemHeader("Expect", "100-Continue"); exchImpl.sendHeadersOnly(); HttpResponseImpl resp = exchImpl.getResponse(); - logResponse(resp); + Utils.logResponse(resp); if (resp.statusCode() != 100) { return resp; } @@ -145,7 +145,7 @@ class Exchange { } else { exchImpl.sendRequest(); HttpResponseImpl resp = exchImpl.getResponse(); - logResponse(resp); + Utils.logResponse(resp); return checkForUpgrade(resp, exchImpl); } } @@ -163,9 +163,7 @@ class Exchange { } SecurityException e = securityCheck(acc); if (e != null) { - CompletableFuture cf = new CompletableFuture<>(); - cf.completeExceptionally(e); - return cf; + return CompletableFuture.failedFuture(e); } if (permissions.size() > 0) { return AccessController.doPrivileged( @@ -182,9 +180,7 @@ class Exchange { try { exchImpl = ExchangeImpl.get(this, connection); } catch (IOException | InterruptedException e) { - CompletableFuture cf = new CompletableFuture<>(); - cf.completeExceptionally(e); - return cf; + return CompletableFuture.failedFuture(e); } if (request.expectContinue()) { request.addSystemHeader("Expect", "100-Continue"); @@ -200,23 +196,19 @@ class Exchange { return exchImpl.sendBodyAsync() .thenCompose(exchImpl::getResponseAsync) .thenApply((r) -> { - logResponse(r); + Utils.logResponse(r); return r; }); } else { Exchange.this.response = r1; - logResponse(r1); + Utils.logResponse(r1); return CompletableFuture.completedFuture(r1); } }); } else { return exchImpl - .sendHeadersAsync() - .thenCompose((Void v) -> { - // send body and get response at same time - return exchImpl.sendBodyAsync() - .thenCompose(exchImpl::getResponseAsync); - }) + .sendRequestAsync() + .thenCompose(exchImpl::getResponseAsync) .thenCompose((HttpResponseImpl r1) -> { int rcode = r1.statusCode(); CompletableFuture cf = @@ -225,13 +217,13 @@ class Exchange { return cf; } else { Exchange.this.response = r1; - logResponse(r1); + Utils.logResponse(r1); return CompletableFuture.completedFuture(r1); } }) .thenApply((HttpResponseImpl response) -> { this.response = response; - logResponse(response); + Utils.logResponse(response); return response; }); } @@ -254,9 +246,9 @@ class Exchange { client.client2(), this) .thenCompose((Http2Connection c) -> { + c.putConnection(); Stream s = c.getStream(1); exchImpl = s; - c.putConnection(); return s.getResponseAsync(null); }) ); @@ -294,21 +286,6 @@ class Exchange { } - private void logResponse(HttpResponseImpl r) { - if (!Log.requests()) - return; - StringBuilder sb = new StringBuilder(); - String method = r.request().method(); - URI uri = r.uri(); - String uristring = uri == null ? "" : uri.toString(); - sb.append('(') - .append(method) - .append(" ") - .append(uristring) - .append(") ") - .append(Integer.toString(r.statusCode())); - Log.logResponse(sb.toString()); - } CompletableFuture responseBodyAsync(HttpResponse.BodyProcessor processor) { return exchImpl.responseBodyAsync(processor); @@ -352,9 +329,9 @@ class Exchange { } String method = request.method(); - HttpHeadersImpl userHeaders = request.getUserHeaders(); + HttpHeaders userHeaders = request.getUserHeaders(); URI u = getURIForSecurityCheck(); - URLPermission p = Utils.getPermission(u, method, userHeaders.directMap()); + URLPermission p = Utils.getPermission(u, method, userHeaders.map()); try { assert acc != null; diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/FrameReader.java b/jdk/src/java.httpclient/share/classes/java/net/http/FrameReader.java new file mode 100644 index 00000000000..5e0d9fb4ebe --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/FrameReader.java @@ -0,0 +1,70 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package java.net.http; + +import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.List; + +/** + * Represents one frame. May be initialized with a leftover buffer from previous + * frame. Call {@code haveFrame()} to determine if buffers contains at least one + * frame. If false, the obtain another buffer and call {@code}input(ByteBuffer)}. + * There may be additional bytes at end of the frame list. + */ +class FrameReader { + + final List buffers; + + FrameReader() { + buffers = new LinkedList<>(); + } + + FrameReader(FrameReader that) { + this.buffers = that.buffers; + } + + FrameReader(ByteBuffer remainder) { + buffers = new LinkedList<>(); + if (remainder != null) { + buffers.add(remainder); + } + } + + public synchronized void input(ByteBuffer buffer) { + buffers.add(buffer); + } + + public synchronized boolean haveFrame() { + //buffers = Utils.superCompact(buffers, () -> ByteBuffer.allocate(Utils.BUFSIZE)); + int size = 0; + for (ByteBuffer buffer : buffers) { + size += buffer.remaining(); + } + if (size < 3) { + return false; // don't have length yet + } + // we at least have length field + int length = 0; + int j = 0; + ByteBuffer b = buffers.get(j); + b.mark(); + for (int i=0; i<3; i++) { + while (!b.hasRemaining()) { + b.reset(); + b = buffers.get(++j); + b.mark(); + } + length = (length << 8) + (b.get() & 0xff); + } + b.reset(); + return (size >= length + 9); // frame length + } + + synchronized List frame() { + return buffers; + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/GoAwayFrame.java b/jdk/src/java.httpclient/share/classes/java/net/http/GoAwayFrame.java new file mode 100644 index 00000000000..7737240d300 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/GoAwayFrame.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; +import java.nio.ByteBuffer; + +class GoAwayFrame extends ErrorFrame { + + GoAwayFrame() { + type = TYPE; + } + + int lastStream; + byte[] debugData = new byte[0]; + + public static final int TYPE = 0x7; + + // Flags + public static final int ACK = 0x1; + + public void setDebugData(byte[] debugData) { + this.debugData = debugData; + } + + @Override + public String toString() { + return super.toString() + " Debugdata: " + new String(debugData); + } + + @Override + String flagAsString(int flag) { + switch (flag) { + case ACK: + return "ACK"; + } + return super.flagAsString(flag); + } + + public void setLastStream(int lastStream) { + this.lastStream = lastStream; + } + + public int getLastStream() { + return this.lastStream; + } + + public byte[] getDebugData() { + return debugData; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + if (length < 8) { + throw new IOException("Invalid GoAway frame"); + } + lastStream = bc.getInt() & 0x7fffffff; + errorCode = bc.getInt(); + //debugData = bc.getBytes(8); + int datalen = length - 8; + if (datalen > 0) { + debugData = bc.getBytes(datalen); + Log.logError("GoAway debugData " + new String(debugData)); + } + } + + @Override + void writeOutgoing(ByteBufferGenerator bg) { + super.writeOutgoing(bg); + ByteBuffer buf = bg.getBuffer(length); + buf.putInt(lastStream); + buf.putInt(errorCode); + if (length > 8) { + buf.put(debugData); + } + } + + @Override + void computeLength() { + length = 8 + debugData.length; + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFrame.java b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFrame.java new file mode 100644 index 00000000000..57440ea6d37 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFrame.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.nio.ByteBuffer; + +/** + * Either a HeadersFrame or a ContinuationFrame + */ +abstract class HeaderFrame extends Http2Frame { + + int offset; + int number; + int headerLength; + ByteBuffer[] headerBlocks; + + public static final int END_HEADERS = 0x4; + + @Override + String flagAsString(int flag) { + switch (flag) { + case END_HEADERS: + return "END_HEADERS"; + } + return super.flagAsString(flag); + } + + /** + * Sets the array of hpack encoded ByteBuffers + */ + public void setHeaderBlock(ByteBuffer bufs[], int offset, int number) { + this.headerBlocks = bufs; + this.offset = offset; + this.number = number; + int length = 0; + for (int i=offset; i request.getAccessControlContext()); + request::getAccessControlContext); operations.add(cf); return cf; } @@ -269,7 +249,7 @@ class Http1Exchange extends ExchangeImpl { cf.completeExceptionally(e); connection.close(); } - }, () -> request.getAccessControlContext()); + }, request::getAccessControlContext); operations.add(cf); return cf; } @@ -302,7 +282,7 @@ class Http1Exchange extends ExchangeImpl { cf.completeExceptionally(e); connection.close(); } - }, () -> request.getAccessControlContext()); + }, request::getAccessControlContext); operations.add(cf); return cf; } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java index f0da88b3b5c..a4fe1943853 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.net.InetSocketAddress; +import java.net.http.HttpConnection.Mode; import java.nio.charset.StandardCharsets; import java.util.function.LongConsumer; import static java.nio.charset.StandardCharsets.US_ASCII; @@ -48,7 +49,8 @@ class Http1Request { // See line 206 and below for description final ByteBuffer[] buffers; final HttpRequest.BodyProcessor requestProc; - final HttpHeadersImpl userHeaders, systemHeaders; + final HttpHeaders userHeaders; + final HttpHeadersImpl systemHeaders; final LongConsumer flowController; boolean streaming; long contentLength; @@ -91,10 +93,10 @@ class Http1Request { private void collectHeaders1(StringBuilder sb, HttpRequestImpl request, - HttpHeadersImpl headers) + HttpHeaders headers) throws IOException { - Map> h = headers.directMap(); + Map> h = headers.map(); Set>> entries = h.entrySet(); for (Map.Entry> entry : entries) { @@ -112,8 +114,6 @@ class Http1Request { } } - private static final int BUFSIZE = 64 * 1024; // TODO: configurable? - private String getPathAndQuery(URI uri) { String path = uri.getPath(); String query = uri.getQuery(); @@ -134,6 +134,25 @@ class Http1Request { return addr.getHostString() + ":" + addr.getPort(); } + private String hostString() { + URI uri = request.uri(); + int port = uri.getPort(); + String host = uri.getHost(); + + boolean defaultPort; + if (port == -1) + defaultPort = true; + else if (request.secure()) + defaultPort = port == 443; + else + defaultPort = port == 80; + + if (defaultPort) + return host; + else + return host + ":" + Integer.toString(port); + } + private String requestURI() { URI uri = request.uri(); String method = request.method(); @@ -161,6 +180,7 @@ class Http1Request { void sendRequest() throws IOException { collectHeaders(); + chan.configureMode(Mode.BLOCKING); if (contentLength == 0) { chan.write(buffers, 0, 2); } else if (contentLength > 0) { @@ -196,7 +216,7 @@ class Http1Request { buffers[0] = ByteBuffer.wrap(cmd.getBytes(StandardCharsets.US_ASCII)); URI uri = request.uri(); if (uri != null) { - systemHeaders.setHeader("Host", uri.getHost()); + systemHeaders.setHeader("Host", hostString()); } if (request == null) { // this is not a user request. No content diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java index 6fad37b6b8f..d0a937ed4e9 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java @@ -24,7 +24,6 @@ package java.net.http; import java.io.IOException; -import java.net.URI; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java b/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java index 4491168225b..2ee03c9de27 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,133 @@ */ package java.net.http; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.URI; +import static java.net.http.SettingsFrame.INITIAL_WINDOW_SIZE; +import static java.net.http.SettingsFrame.ENABLE_PUSH; +import static java.net.http.SettingsFrame.HEADER_TABLE_SIZE; +import static java.net.http.SettingsFrame.MAX_CONCURRENT_STREAMS; +import static java.net.http.SettingsFrame.MAX_FRAME_SIZE; +import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Http2 specific aspects of HttpClientImpl + */ class Http2ClientImpl { - Http2ClientImpl(HttpClientImpl t) {} - String getSettingsString() {return "";} - void debugPrint() {} - Http2Connection getConnectionFor(HttpRequestImpl r) { - return null; + + final private HttpClientImpl client; + + Http2ClientImpl(HttpClientImpl client) { + this.client = client; + } + + /* Map key is "scheme:host:port" */ + final private Map connections = + Collections.synchronizedMap(new HashMap<>()); + + final private Set opening = Collections.synchronizedSet(new HashSet<>()); + + synchronized boolean haveConnectionFor(URI uri, InetSocketAddress proxy) { + return connections.containsKey(Http2Connection.keyFor(uri,proxy)); + } + + /** + * If a https request then blocks and waits until a connection is opened. + * Returns null if the request is 'http' as a different (upgrade) + * mechanism is used. + * + * Only one connection per destination is created. Blocks when opening + * connection, or when waiting for connection to be opened. + * First thread opens the connection and notifies the others when done. + * + * If the request is secure (https) then we open the connection here. + * If not, then the more complicated upgrade from 1.1 to 2 happens (not here) + * In latter case, when the Http2Connection is connected, putConnection() must + * be called to store it. + */ + Http2Connection getConnectionFor(HttpRequestImpl req) + throws IOException, InterruptedException { + URI uri = req.uri(); + InetSocketAddress proxy = req.proxy(); + String key = Http2Connection.keyFor(uri, proxy); + Http2Connection connection; + synchronized (opening) { + while ((connection = connections.get(key)) == null) { + if (!req.secure()) { + return null; + } + if (!opening.contains(key)) { + opening.add(key); + break; + } else { + opening.wait(); + } + } + } + if (connection != null) { + return connection; + } + // we are opening the connection here blocking until it is done. + connection = new Http2Connection(req); + synchronized (opening) { + connections.put(key, connection); + opening.remove(key); + opening.notifyAll(); + } + return connection; + } + + + /* + * TODO: If there isn't a connection to the same destination, then + * store it. If there is already a connection, then close it + */ + synchronized void putConnection(Http2Connection c) { + String key = c.key(); + connections.put(key, c); + } + + synchronized void deleteConnection(Http2Connection c) { + String key = c.key(); + connections.remove(key); + } + + HttpClientImpl client() { + return client; + } + + /** Returns the client settings as a base64 (url) encoded string */ + String getSettingsString() { + SettingsFrame sf = getClientSettings(); + ByteBufferGenerator bg = new ByteBufferGenerator(client); + sf.writeOutgoing(bg); + byte[] settings = bg.asByteArray(9); // without the header + Base64.Encoder encoder = Base64.getUrlEncoder() + .withoutPadding(); + return encoder.encodeToString(settings); + } + + private static final int K = 1024; + + SettingsFrame getClientSettings() { + SettingsFrame frame = new SettingsFrame(); + frame.setParameter(HEADER_TABLE_SIZE, Utils.getIntegerNetProperty( + "java.net.httpclient.hpack.maxheadertablesize", 16 * K)); + frame.setParameter(ENABLE_PUSH, Utils.getIntegerNetProperty( + "java.net.httpclient.enablepush", 1)); + frame.setParameter(MAX_CONCURRENT_STREAMS, Utils.getIntegerNetProperty( + "java.net.httpclient.maxstreams", 16)); + frame.setParameter(INITIAL_WINDOW_SIZE, Utils.getIntegerNetProperty( + "java.net.httpclient.windowsize", 32 * K)); + frame.setParameter(MAX_FRAME_SIZE, Utils.getIntegerNetProperty( + "java.net.httpclient.maxframesize", 16 * K)); + frame.computeLength(); + return frame; } } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java index 3f60c4f805e..75eab0f2f34 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * 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,42 +24,767 @@ package java.net.http; import java.io.IOException; -import java.net.Authenticator; -import java.net.CookieManager; -import java.net.ProxySelector; +import java.net.InetSocketAddress; import java.net.URI; -import static java.net.http.Utils.BUFSIZE; +import java.net.http.HttpConnection.Mode; import java.nio.ByteBuffer; -import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; -import static java.nio.channels.SelectionKey.OP_CONNECT; -import static java.nio.channels.SelectionKey.OP_READ; -import static java.nio.channels.SelectionKey.OP_WRITE; -import java.nio.channels.Selector; +import java.nio.charset.StandardCharsets; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Set; -import java.util.concurrent.*; -import java.security.NoSuchAlgorithmException; -import java.util.ListIterator; -import java.util.Optional; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLParameters; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import sun.net.httpclient.hpack.Encoder; +import sun.net.httpclient.hpack.Decoder; +import static java.net.http.SettingsFrame.*; +import static java.net.http.Utils.BUFSIZE; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Formatter; +import java.util.stream.Collectors; +import sun.net.httpclient.hpack.DecodingCallback; -class Http2Connection { - static CompletableFuture createAsync( - HttpConnection connection, Http2ClientImpl client2, Exchange exchange) { - return null; - } +/** + * An Http2Connection. Encapsulates the socket(channel) and any SSLEngine used + * over it. Contains an HttpConnection which hides the SocketChannel SSL stuff. + * + * Http2Connections belong to a Http2ClientImpl, (one of) which belongs + * to a HttpClientImpl. + * + * Creation cases: + * 1) upgraded HTTP/1.1 plain tcp connection + * 2) prior knowledge directly created plain tcp connection + * 3) directly created HTTP/2 SSL connection which uses ALPN. + * + * Sending is done by writing directly to underlying HttpConnection object which + * is operating in async mode. No flow control applies on output at this level + * and all writes are just executed as puts to an output Q belonging to HttpConnection + * Flow control is implemented by HTTP/2 protocol itself. + * + * Hpack header compression + * and outgoing stream creation is also done here, because these operations + * must be synchronized at the socket level. Stream objects send frames simply + * by placing them on the connection's output Queue. sendFrame() is called + * from a higher level (Stream) thread. + * + * asyncReceive(ByteBuffer) is always called from the selector thread. It assembles + * incoming Http2Frames, and directs them to the appropriate Stream.incoming() + * or handles them directly itself. This thread performs hpack decompression + * and incoming stream creation (Server push). Incoming frames destined for a + * stream are provided by calling Stream.incoming(). + */ +class Http2Connection implements BufferHandler { + final Queue outputQ; + volatile boolean closed; + + //------------------------------------- + final HttpConnection connection; + HttpClientImpl client; + final Http2ClientImpl client2; + Map streams; + int nextstreamid = 3; // stream 1 is registered separately + int nextPushStream = 2; + Encoder hpackOut; + Decoder hpackIn; + SettingsFrame clientSettings, serverSettings; + ByteBufferConsumer bbc; + final LinkedList freeList; + final String key; // for HttpClientImpl.connections map + FrameReader reader; + + // Connection level flow control windows + int sendWindow = INITIAL_WINDOW_SIZE; + + final static int DEFAULT_FRAME_SIZE = 16 * 1024; + private static ByteBuffer[] empty = Utils.EMPTY_BB_ARRAY; + + final ExecutorWrapper executor; + + /** + * This is established by the protocol spec and the peer will update it with + * WINDOW_UPDATEs, which affects the sendWindow. + */ + final static int INITIAL_WINDOW_SIZE = 64 * 1024 - 1; + + // TODO: need list of control frames from other threads + // that need to be sent + + /** + * Case 1) Create from upgraded HTTP/1.1 connection. + * Is ready to use. Will not be SSL. exchange is the Exchange + * that initiated the connection, whose response will be delivered + * on a Stream. + */ Http2Connection(HttpConnection connection, Http2ClientImpl client2, Exchange exchange) throws IOException, InterruptedException { + this.outputQ = new Queue<>(); + String msg = "Connection send window size " + Integer.toString(sendWindow); + Log.logTrace(msg); + + //this.initialExchange = exchange; + assert !(connection instanceof SSLConnection); + this.connection = connection; + this.client = client2.client(); + this.client2 = client2; + this.executor = client.executorWrapper(); + this.freeList = new LinkedList<>(); + this.key = keyFor(connection); + streams = Collections.synchronizedMap(new HashMap<>()); + initCommon(); + //sendConnectionPreface(); + Stream initialStream = createStream(exchange); + initialStream.registerStream(1); + initialStream.requestSent(); + sendConnectionPreface(); + connection.configureMode(Mode.ASYNC); + // start reading and writing + // start reading + AsyncConnection asyncConn = (AsyncConnection)connection; + asyncConn.setAsyncCallbacks(this::asyncReceive, this::shutdown); + asyncReceive(connection.getRemaining()); + asyncConn.startReading(); } - Stream getStream(int i) {return null;} - Stream createStream(Exchange ex) {return null;} - void putConnection() {} + // async style but completes immediately + static CompletableFuture createAsync(HttpConnection connection, + Http2ClientImpl client2, Exchange exchange) { + CompletableFuture cf = new CompletableFuture<>(); + try { + Http2Connection c = new Http2Connection(connection, client2, exchange); + cf.complete(c); + } catch (IOException | InterruptedException e) { + cf.completeExceptionally(e); + } + return cf; + } + + /** + * Cases 2) 3) + * + * request is request to be sent. + */ + Http2Connection(HttpRequestImpl request) throws IOException, InterruptedException { + InetSocketAddress proxy = request.proxy(); + URI uri = request.uri(); + InetSocketAddress addr = Utils.getAddress(request); + String msg = "Connection send window size " + Integer.toString(sendWindow); + Log.logTrace(msg); + this.key = keyFor(uri, proxy); + this.connection = HttpConnection.getConnection(addr, request, this); + streams = Collections.synchronizedMap(new HashMap<>()); + this.client = request.client(); + this.client2 = client.client2(); + this.executor = client.executorWrapper(); + this.freeList = new LinkedList<>(); + this.outputQ = new Queue<>(); + nextstreamid = 1; + initCommon(); + connection.connect(); + connection.configureMode(Mode.ASYNC); + // start reading + AsyncConnection asyncConn = (AsyncConnection)connection; + asyncConn.setAsyncCallbacks(this::asyncReceive, this::shutdown); + sendConnectionPreface(); + asyncConn.startReading(); + } + + // NEW + synchronized void obtainSendWindow(int amount) throws InterruptedException { + while (amount > 0) { + int n = Math.min(amount, sendWindow); + sendWindow -= n; + amount -= n; + if (amount > 0) + wait(); + } + } + + synchronized void updateSendWindow(int amount) { + if (sendWindow == 0) { + sendWindow += amount; + notifyAll(); + } else + sendWindow += amount; + } + + synchronized int sendWindow() { + return sendWindow; + } + + static String keyFor(HttpConnection connection) { + boolean isProxy = connection.isProxied(); + boolean isSecure = connection.isSecure(); + InetSocketAddress addr = connection.address(); + + return keyString(isSecure, isProxy, addr.getHostString(), addr.getPort()); + } + + static String keyFor(URI uri, InetSocketAddress proxy) { + boolean isSecure = uri.getScheme().equalsIgnoreCase("https"); + boolean isProxy = proxy != null; + + String host; + int port; + + if (isProxy) { + host = proxy.getHostString(); + port = proxy.getPort(); + } else { + host = uri.getHost(); + port = uri.getPort(); + } + return keyString(isSecure, isProxy, host, port); + } + + // {C,S}:{H:P}:host:port + // C indicates clear text connection "http" + // S indicates secure "https" + // H indicates host (direct) connection + // P indicates proxy + // Eg: "S:H:foo.com:80" + static String keyString(boolean secure, boolean proxy, String host, int port) { + char c1 = secure ? 'S' : 'C'; + char c2 = proxy ? 'P' : 'H'; + + StringBuilder sb = new StringBuilder(128); + sb.append(c1).append(':').append(c2).append(':') + .append(host).append(':').append(port); + return sb.toString(); + } + + String key() { + return this.key; + } + + void putConnection() { + client2.putConnection(this); + } + + private static String toHexdump1(ByteBuffer bb) { + bb.mark(); + StringBuilder sb = new StringBuilder(512); + Formatter f = new Formatter(sb); + + while (bb.hasRemaining()) { + int i = Byte.toUnsignedInt(bb.get()); + f.format("%02x:", i); + } + sb.deleteCharAt(sb.length()-1); + bb.reset(); + return sb.toString(); + } + + private static String toHexdump(ByteBuffer bb) { + List words = new ArrayList<>(); + int i = 0; + bb.mark(); + while (bb.hasRemaining()) { + if (i % 2 == 0) { + words.add(""); + } + byte b = bb.get(); + String hex = Integer.toHexString(256 + Byte.toUnsignedInt(b)).substring(1); + words.set(i / 2, words.get(i / 2) + hex); + i++; + } + bb.reset(); + return words.stream().collect(Collectors.joining(" ")); + } + + private void decodeHeaders(HeaderFrame frame, DecodingCallback decoder) { + boolean endOfHeaders = frame.getFlag(HeaderFrame.END_HEADERS); + + ByteBuffer[] buffers = frame.getHeaderBlock(); + for (int i = 0; i < buffers.length; i++) { + hpackIn.decode(buffers[i], endOfHeaders, decoder); + } + } + + int getInitialSendWindowSize() { + return serverSettings.getParameter(SettingsFrame.INITIAL_WINDOW_SIZE); + } + + void close() { + GoAwayFrame f = new GoAwayFrame(); + f.setDebugData("Requested by user".getBytes()); + // TODO: set last stream. For now zero ok. + sendFrame(f); + } + + // BufferHandler methods + + @Override + public ByteBuffer getBuffer(int n) { + return client.getBuffer(n); + } + + @Override + public void returnBuffer(ByteBuffer buf) { + client.returnBuffer(buf); + } + + @Override + public void setMinBufferSize(int n) { + client.setMinBufferSize(n); + } + + private final Object readlock = new Object(); + + void asyncReceive(ByteBuffer buffer) { + synchronized (readlock) { + try { + if (reader == null) { + reader = new FrameReader(buffer); + } else { + reader.input(buffer); + } + while (true) { + if (reader.haveFrame()) { + List buffers = reader.frame(); + + ByteBufferConsumer bbc = new ByteBufferConsumer(buffers, this::getBuffer); + processFrame(bbc); + if (bbc.consumed()) { + reader = new FrameReader(); + return; + } else { + reader = new FrameReader(reader); + } + } else + return; + } + } catch (Throwable e) { + String msg = Utils.stackTrace(e); + Log.logTrace(msg); + shutdown(e); + } + } + } + + void shutdown(Throwable t) { + System.err.println("Shutdown: " + t); + t.printStackTrace(); + closed = true; + client2.deleteConnection(this); + Collection c = streams.values(); + for (Stream s : c) { + s.cancelImpl(t); + } + connection.close(); + } + + /** + * Handles stream 0 (common) frames that apply to whole connection and passes + * other stream specific frames to that Stream object. + * + * Invokes Stream.incoming() which is expected to process frame without + * blocking. + */ + void processFrame(ByteBufferConsumer bbc) throws IOException, InterruptedException { + Http2Frame frame = Http2Frame.readIncoming(bbc); + Log.logFrames(frame, "IN"); + int streamid = frame.streamid(); + if (streamid == 0) { + handleCommonFrame(frame); + } else { + Stream stream = getStream(streamid); + if (stream == null) { + // should never receive a frame with unknown stream id + resetStream(streamid, ResetFrame.PROTOCOL_ERROR); + } + if (frame instanceof PushPromiseFrame) { + PushPromiseFrame pp = (PushPromiseFrame)frame; + handlePushPromise(stream, pp); + } else if (frame instanceof HeaderFrame) { + // decode headers (or continuation) + decodeHeaders((HeaderFrame) frame, stream.rspHeadersConsumer()); + stream.incoming(frame); + } else + stream.incoming(frame); + } + } + + private void handlePushPromise(Stream parent, PushPromiseFrame pp) + throws IOException, InterruptedException { + + HttpRequestImpl parentReq = parent.request; + int promisedStreamid = pp.getPromisedStream(); + if (promisedStreamid != nextPushStream) { + resetStream(promisedStreamid, ResetFrame.PROTOCOL_ERROR); + return; + } else { + nextPushStream += 2; + } + HeaderDecoder decoder = new HeaderDecoder(); + decodeHeaders(pp, decoder); + HttpHeadersImpl headers = decoder.headers(); + HttpRequestImpl pushReq = HttpRequestImpl.createPushRequest(parentReq, headers); + + Stream.PushedStream pushStream = createPushStream(parent, pushReq); + pushStream.registerStream(promisedStreamid); + parent.incoming_pushPromise(pushReq, pushStream); + } + + private void handleCommonFrame(Http2Frame frame) + throws IOException, InterruptedException { + + switch (frame.type()) { + case SettingsFrame.TYPE: + { SettingsFrame f = (SettingsFrame)frame; + handleSettings(f);} + break; + case PingFrame.TYPE: + { PingFrame f = (PingFrame)frame; + handlePing(f);} + break; + case GoAwayFrame.TYPE: + { GoAwayFrame f = (GoAwayFrame)frame; + handleGoAway(f);} + break; + case WindowUpdateFrame.TYPE: + { WindowUpdateFrame f = (WindowUpdateFrame)frame; + handleWindowUpdate(f);} + break; + default: + protocolError(ErrorFrame.PROTOCOL_ERROR); + } + } + + void resetStream(int streamid, int code) throws IOException, InterruptedException { + Log.logError( + "Resetting stream {0,number,integer} with error code {1,number,integer}", + streamid, code); + ResetFrame frame = new ResetFrame(); + frame.streamid(streamid); + frame.setErrorCode(code); + sendFrame(frame); + streams.remove(streamid); + } + + private void handleWindowUpdate(WindowUpdateFrame f) + throws IOException, InterruptedException { + updateSendWindow(f.getUpdate()); + } + + private void protocolError(int errorCode) + throws IOException, InterruptedException { + GoAwayFrame frame = new GoAwayFrame(); + frame.setErrorCode(errorCode); + sendFrame(frame); + String msg = "Error code: " + errorCode; + shutdown(new IOException("protocol error")); + } + + private void handleSettings(SettingsFrame frame) + throws IOException, InterruptedException { + if (frame.getFlag(SettingsFrame.ACK)) { + // ignore ack frames for now. + return; + } + serverSettings = frame; + SettingsFrame ack = getAckFrame(frame.streamid()); + sendFrame(ack); + } + + private void handlePing(PingFrame frame) + throws IOException, InterruptedException { + frame.setFlag(PingFrame.ACK); + sendFrame(frame); + } + + private void handleGoAway(GoAwayFrame frame) + throws IOException, InterruptedException { + //System.err.printf("GoAWAY: %s\n", ErrorFrame.stringForCode(frame.getErrorCode())); + shutdown(new IOException("GOAWAY received")); + } + + private void initCommon() { + clientSettings = client2.getClientSettings(); + + // serverSettings will be updated by server + serverSettings = SettingsFrame.getDefaultSettings(); + hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE)); + hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE)); + } + + /** + * Max frame size we are allowed to send + */ + public int getMaxSendFrameSize() { + int param = serverSettings.getParameter(MAX_FRAME_SIZE); + if (param == -1) { + param = DEFAULT_FRAME_SIZE; + } + return param; + } + + /** + * Max frame size we will receive + */ + public int getMaxReceiveFrameSize() { + return clientSettings.getParameter(MAX_FRAME_SIZE); + } + + // Not sure how useful this is. + public int getMaxHeadersSize() { + return serverSettings.getParameter(MAX_HEADER_LIST_SIZE); + } + + private static final String CLIENT_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; + + private static final byte[] PREFACE_BYTES = + CLIENT_PREFACE.getBytes(StandardCharsets.ISO_8859_1); + + /** + * Sends Connection preface and Settings frame with current preferred + * values + */ + private void sendConnectionPreface() throws IOException { + ByteBufferGenerator bg = new ByteBufferGenerator(this); + bg.getBuffer(PREFACE_BYTES.length).put(PREFACE_BYTES); + ByteBuffer[] ba = bg.getBufferArray(); + connection.write(ba, 0, ba.length); + + bg = new ByteBufferGenerator(this); + SettingsFrame sf = client2.getClientSettings(); + Log.logFrames(sf, "OUT"); + sf.writeOutgoing(bg); + WindowUpdateFrame wup = new WindowUpdateFrame(); + wup.streamid(0); + // send a Window update for the receive buffer we are using + // minus the initial 64 K specified in protocol + wup.setUpdate(client2.client().getReceiveBufferSize() - (64 * 1024 - 1)); + wup.computeLength(); + wup.writeOutgoing(bg); + Log.logFrames(wup, "OUT"); + ba = bg.getBufferArray(); + connection.write(ba, 0, ba.length); + } + + /** + * Returns an existing Stream with given id, or null if doesn't exist + */ + Stream getStream(int streamid) { + return streams.get(streamid); + } + + /** + * Creates Stream with given id. + */ + Stream createStream(Exchange exchange) { + Stream stream = new Stream(client, this, exchange); + return stream; + } + + Stream.PushedStream createPushStream(Stream parent, HttpRequestImpl pushReq) { + Stream.PushGroup pg = parent.request.pushGroup(); + return new Stream.PushedStream(pg, client, this, parent, pushReq); + } + + void putStream(Stream stream, int streamid) { + streams.put(streamid, stream); + } + + void deleteStream(Stream stream) { + streams.remove(stream.streamid); + } + + static final int MAX_STREAM = Integer.MAX_VALUE - 2; + + // Number of header bytes in a Headers Frame + final static int HEADERS_HEADER_SIZE = 15; + + // Number of header bytes in a Continuation frame + final static int CONTIN_HEADER_SIZE = 9; + + /** + * Encode the headers into a List and then create HEADERS + * and CONTINUATION frames from the list and return the List. + * + * @param frame + * @return + */ + private LinkedList encodeHeaders(OutgoingHeaders frame) { + LinkedList buffers = new LinkedList<>(); + ByteBuffer buf = getBuffer(); + buffers.add(buf); + encodeHeadersImpl(frame.stream.getRequestPseudoHeaders(), buffers); + encodeHeadersImpl(frame.getUserHeaders(), buffers); + encodeHeadersImpl(frame.getSystemHeaders(), buffers); + + for (ByteBuffer b : buffers) { + b.flip(); + } + + LinkedList frames = new LinkedList<>(); + int maxframesize = getMaxSendFrameSize(); + + HeadersFrame oframe = new HeadersFrame(); + oframe.setFlags(frame.getFlags()); + oframe.streamid(frame.streamid()); + + oframe.setHeaderBlock(getBufferArray(buffers, maxframesize)); + frames.add(oframe); + // Any buffers left? + boolean done = buffers.isEmpty(); + if (done) { + oframe.setFlag(HeaderFrame.END_HEADERS); + } else { + ContinuationFrame cf = null; + while (!done) { + cf = new ContinuationFrame(); + cf.streamid(frame.streamid()); + cf.setHeaderBlock(getBufferArray(buffers, maxframesize)); + frames.add(cf); + done = buffers.isEmpty(); + } + cf.setFlag(HeaderFrame.END_HEADERS); + } + return frames; + } + + // should always return at least one buffer + private static ByteBuffer[] getBufferArray(LinkedList list, int maxsize) { + assert maxsize >= BUFSIZE; + LinkedList newlist = new LinkedList<>(); + int size = list.size(); + int nbytes = 0; + for (int i=0; i buffers) { + ByteBuffer buffer; + if (!(buffer = buffers.getLast()).hasRemaining()) { + buffer = getBuffer(); + buffers.add(buffer); + } + for (Map.Entry> e : hdrs.map().entrySet()) { + String key = e.getKey(); + String lkey = key.toLowerCase(); + List values = e.getValue(); + for (String value : values) { + hpackOut.header(lkey, value); + boolean encoded = false; + do { + encoded = hpackOut.encode(buffer); + if (!encoded) { + buffer = getBuffer(); + buffers.add(buffer); + } + } while (!encoded); + } + } + } + + public void sendFrames(List frames) throws IOException, InterruptedException { + for (Http2Frame frame : frames) { + sendFrame(frame); + } + } + + static Throwable getExceptionFrom(CompletableFuture cf) { + try { + cf.get(); + return null; + } catch (Throwable e) { + if (e.getCause() != null) + return e.getCause(); + else + return e; + } + } + + + void execute(Runnable r) { + executor.execute(r, null); + } + + private final Object sendlock = new Object(); + + /** + * + */ + void sendFrame(Http2Frame frame) { + synchronized (sendlock) { + try { + if (frame instanceof OutgoingHeaders) { + OutgoingHeaders oh = (OutgoingHeaders) frame; + Stream stream = oh.getStream(); + stream.registerStream(nextstreamid); + oh.streamid(nextstreamid); + nextstreamid += 2; + // set outgoing window here. This allows thread sending + // body to proceed. + stream.updateOutgoingWindow(getInitialSendWindowSize()); + LinkedList frames = encodeHeaders(oh); + for (Http2Frame f : frames) { + sendOneFrame(f); + } + } else { + sendOneFrame(frame); + } + + } catch (IOException e) { + if (!closed) { + Log.logError(e); + shutdown(e); + } + } + } + } + + /** + * Send a frame. + * + * @param frame + * @throws IOException + */ + private void sendOneFrame(Http2Frame frame) throws IOException { + ByteBufferGenerator bbg = new ByteBufferGenerator(this); + frame.computeLength(); + Log.logFrames(frame, "OUT"); + frame.writeOutgoing(bbg); + ByteBuffer[] currentBufs = bbg.getBufferArray(); + connection.write(currentBufs, 0, currentBufs.length); + } + + + private SettingsFrame getAckFrame(int streamid) { + SettingsFrame frame = new SettingsFrame(); + frame.setFlag(SettingsFrame.ACK); + frame.streamid(streamid); + return frame; + } + + static class HeaderDecoder implements DecodingCallback { + HttpHeadersImpl headers; + + HeaderDecoder() { + this.headers = new HttpHeadersImpl(); + } + + @Override + public void onDecoded(CharSequence name, CharSequence value) { + headers.addHeader(name.toString(), value.toString()); + } + + HttpHeadersImpl headers() { + return headers; + } + } } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Http2Frame.java b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Frame.java new file mode 100644 index 00000000000..273fb75fc32 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Frame.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ +package java.net.http; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * When sending a frame, the length field must be set in sub-class + * by calling computeLength() + */ +abstract class Http2Frame { + + int length = -1; + int type; + int streamid; + int flags; + + // called when reading in only + void initCommon(int length, int type, int streamid, int flags) { + this.length = length; + this.type = type; + this.streamid = streamid; + this.flags = flags; + } + + public int length() { + return length; + } + + public int type() { + return type; + } + + public int streamid() { + return streamid; + } + + public void setFlag(int flag) { + flags |= flag; + } + + public void setFlags(int flags) { + this.flags = flags; + } + + public int getFlags() { + return flags; + } + + public boolean getFlag(int flag) { + return (flags & flag) != 0; + } + + public void clearFlag(int flag) { + flags &= 0xffffffff ^ flag; + } + + public void streamid(int streamid) { + this.streamid = streamid; + } + + abstract void readIncomingImpl(ByteBufferConsumer bc) throws IOException; + + /** + * assume given array contains at least one complete frame. + */ + static Http2Frame readIncoming(ByteBufferConsumer bc) throws IOException { + int x = bc.getInt(); + int length = x >> 8; + int type = x & 0xff; + int flags = bc.getByte(); + int streamid = bc.getInt(); + Http2Frame f = null; + switch (type) { + case DataFrame.TYPE: + f = new DataFrame(); + break; + case HeadersFrame.TYPE: + f = new HeadersFrame(); + break; + case ContinuationFrame.TYPE: + f = new ContinuationFrame(); + break; + case ResetFrame.TYPE: + f = new ResetFrame(); + break; + case PriorityFrame.TYPE: + f = new PriorityFrame(); + break; + case SettingsFrame.TYPE: + f = new SettingsFrame(); + break; + case GoAwayFrame.TYPE: + f = new GoAwayFrame(); + break; + case PingFrame.TYPE: + f = new PingFrame(); + break; + case PushPromiseFrame.TYPE: + f = new PushPromiseFrame(); + break; + case WindowUpdateFrame.TYPE: + f = new WindowUpdateFrame(); + break; + default: + String msg = Integer.toString(type); + throw new IOException("unknown frame type " + msg); + } + f.initCommon(length, type, streamid, flags); + f.readIncomingImpl(bc); + return f; + } + + public String typeAsString() { + return asString(this.type); + } + + public static String asString(int type) { + switch (type) { + case DataFrame.TYPE: + return "DATA"; + case HeadersFrame.TYPE: + return "HEADERS"; + case ContinuationFrame.TYPE: + return "CONTINUATION"; + case ResetFrame.TYPE: + return "RESET"; + case PriorityFrame.TYPE: + return "PRIORITY"; + case SettingsFrame.TYPE: + return "SETTINGS"; + case GoAwayFrame.TYPE: + return "GOAWAY"; + case PingFrame.TYPE: + return "PING"; + case PushPromiseFrame.TYPE: + return "PUSH_PROMISE"; + case WindowUpdateFrame.TYPE: + return "WINDOW_UPDATE"; + default: + return "UNKNOWN"; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(typeAsString()) + .append(": length=") + .append(Integer.toString(length)) + .append(", streamid=") + .append(streamid) + .append(", flags="); + + int f = flags; + int i = 0; + if (f == 0) { + sb.append("0 "); + } else { + while (f != 0) { + if ((f & 1) == 1) { + sb.append(flagAsString(1 << i)) + .append(' '); + } + f = f >> 1; + i++; + } + } + return sb.toString(); + } + + // Override + String flagAsString(int f) { + return "unknown"; + } + + abstract void computeLength(); + + void writeOutgoing(ByteBufferGenerator bg) { + if (length == -1) { + throw new InternalError("Length not set on outgoing frame"); + } + ByteBuffer buf = bg.getBuffer(9); + int x = (length << 8) + type; + buf.putInt(x); + buf.put((byte)flags); + buf.putInt(streamid); + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java index fd1ab0b012d..0d20fa9a8a9 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java @@ -23,28 +23,32 @@ */ package java.net.http; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; import java.io.IOException; import java.net.Authenticator; import java.net.CookieManager; import java.net.ProxySelector; import java.net.URI; -import static java.net.http.Utils.BUFSIZE; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; -import static java.nio.channels.SelectionKey.OP_CONNECT; -import static java.nio.channels.SelectionKey.OP_READ; -import static java.nio.channels.SelectionKey.OP_WRITE; import java.nio.channels.Selector; -import java.util.*; -import java.util.stream.Stream; -import java.util.concurrent.ExecutorService; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLParameters; +import java.util.stream.Stream; + +import static java.net.http.Utils.BUFSIZE; /** * Client implementation. Contains all configuration information and also @@ -53,6 +57,9 @@ import javax.net.ssl.SSLParameters; */ class HttpClientImpl extends HttpClient implements BufferHandler { + private static final ThreadFactory defaultFactory = + (r -> new Thread(null, r, "HttpClient_worker", 0, true)); + private final CookieManager cookieManager; private final Redirect followRedirects; private final ProxySelector proxySelector; @@ -67,7 +74,6 @@ class HttpClientImpl extends HttpClient implements BufferHandler { private final SelectorManager selmgr; private final FilterFactory filters; private final Http2ClientImpl client2; - private static final ThreadFactory defaultFactory = Executors.defaultThreadFactory(); private final LinkedList timeouts; public static HttpClientImpl create(HttpClientBuilderImpl builder) { @@ -115,7 +121,6 @@ class HttpClientImpl extends HttpClient implements BufferHandler { throw new InternalError(e); } selmgr.setDaemon(true); - selmgr.setName("HttpSelector"); filters = new FilterFactory(); initFilters(); } @@ -135,7 +140,7 @@ class HttpClientImpl extends HttpClient implements BufferHandler { * 4) - mark connection as blocking * 5) - call AsyncEvent.handle() * - * If exchange needs to block again, then call registerEvent() again + * If exchange needs to block again, then call registerEvent() again */ void registerEvent(AsyncEvent exchange) throws IOException { selmgr.register(exchange); @@ -145,35 +150,56 @@ class HttpClientImpl extends HttpClient implements BufferHandler { return client2; } - LinkedList freelist = new LinkedList<>(); + /** + * We keep one size of buffer on free list. That size may increase + * depending on demand. If that happens we dispose of free buffers + * that are smaller than new size. + */ + private final LinkedList freelist = new LinkedList<>(); + int currentSize = BUFSIZE; @Override - public synchronized ByteBuffer getBuffer() { - if (freelist.isEmpty()) { - return ByteBuffer.allocate(BUFSIZE); + public synchronized ByteBuffer getBuffer(int size) { + + ByteBuffer buf; + if (size == -1) + size = currentSize; + + if (size > currentSize) + currentSize = size; + + while (!freelist.isEmpty()) { + buf = freelist.removeFirst(); + if (buf.capacity() < currentSize) + continue; + buf.clear(); + return buf; } - return freelist.removeFirst(); + return ByteBuffer.allocate(size); } @Override public synchronized void returnBuffer(ByteBuffer buffer) { - buffer.clear(); freelist.add(buffer); } + @Override + public synchronized void setMinBufferSize(int n) { + currentSize = Math.max(n, currentSize); + } // Main loop for this client's selector + private final class SelectorManager extends Thread { - class SelectorManager extends Thread { - final Selector selector; - boolean closed; - - final List readyList; - final List registrations; + private final Selector selector; + private volatile boolean closed; + private final List readyList; + private final List registrations; SelectorManager() throws IOException { - readyList = new LinkedList<>(); - registrations = new LinkedList<>(); + super(null, null, "SelectorManager", 0, false); + readyList = new ArrayList<>(); + registrations = new ArrayList<>(); selector = Selector.open(); } @@ -193,32 +219,13 @@ class HttpClientImpl extends HttpClient implements BufferHandler { closed = true; try { selector.close(); - } catch (IOException e) {} - } - - private List copy(List list) { - LinkedList c = new LinkedList<>(); - for (AsyncEvent e : list) { - c.add(e); - } - return c; - } - - String opvals(int i) { - StringBuilder sb = new StringBuilder(); - if ((i & OP_READ) != 0) - sb.append("OP_READ "); - if ((i & OP_CONNECT) != 0) - sb.append("OP_CONNECT "); - if ((i & OP_WRITE) != 0) - sb.append("OP_WRITE "); - return sb.toString(); + } catch (IOException ignored) { } } @Override public void run() { try { - while (true) { + while (!Thread.currentThread().isInterrupted()) { synchronized (this) { for (AsyncEvent exchange : registrations) { SelectableChannel c = exchange.channel(); @@ -229,7 +236,7 @@ class HttpClientImpl extends HttpClient implements BufferHandler { if (key == null) { sa = new SelectorAttachment(c, selector); } else { - sa = (SelectorAttachment)key.attachment(); + sa = (SelectorAttachment) key.attachment(); } sa.register(exchange); } catch (IOException e) { @@ -243,6 +250,7 @@ class HttpClientImpl extends HttpClient implements BufferHandler { } long timeval = getTimeoutValue(); long now = System.currentTimeMillis(); + //debugPrint(selector); int n = selector.select(timeval); if (n == 0) { signalTimeouts(now); @@ -251,7 +259,7 @@ class HttpClientImpl extends HttpClient implements BufferHandler { Set keys = selector.selectedKeys(); for (SelectionKey key : keys) { - SelectorAttachment sa = (SelectorAttachment)key.attachment(); + SelectorAttachment sa = (SelectorAttachment) key.attachment(); int eventsOccurred = key.readyOps(); sa.events(eventsOccurred).forEach(readyList::add); sa.resetInterestOps(eventsOccurred); @@ -260,10 +268,8 @@ class HttpClientImpl extends HttpClient implements BufferHandler { selector.selectedKeys().clear(); for (AsyncEvent exchange : readyList) { - if (exchange instanceof AsyncEvent.Blocking) { + if (exchange.blocking()) { exchange.channel().configureBlocking(true); - } else { - assert exchange instanceof AsyncEvent.NonBlocking; } executor.synchronize(); handleEvent(exchange); // will be delegated to executor @@ -272,14 +278,26 @@ class HttpClientImpl extends HttpClient implements BufferHandler { } } catch (Throwable e) { if (!closed) { - System.err.println("HttpClientImpl terminating on error"); // This terminates thread. So, better just print stack trace String err = Utils.stackTrace(e); Log.logError("HttpClientImpl: fatal error: " + err); } + } finally { + shutdown(); } } + void debugPrint(Selector selector) { + System.err.println("Selector: debugprint start"); + Set keys = selector.keys(); + for (SelectionKey key : keys) { + SelectableChannel c = key.channel(); + int ops = key.interestOps(); + System.err.printf("selector chan:%s ops:%d\n", c, ops); + } + System.err.println("Selector: debugprint end"); + } + void handleEvent(AsyncEvent e) { if (closed) { e.abort(); @@ -303,7 +321,7 @@ class HttpClientImpl extends HttpClient implements BufferHandler { private final SelectableChannel chan; private final Selector selector; private final ArrayList pending; - private int interestops; + private int interestOps; SelectorAttachment(SelectableChannel chan, Selector selector) { this.pending = new ArrayList<>(); @@ -312,53 +330,53 @@ class HttpClientImpl extends HttpClient implements BufferHandler { } void register(AsyncEvent e) throws ClosedChannelException { - int newops = e.interestOps(); - boolean reRegister = (interestops & newops) != newops; - interestops |= newops; + int newOps = e.interestOps(); + boolean reRegister = (interestOps & newOps) != newOps; + interestOps |= newOps; pending.add(e); if (reRegister) { // first time registration happens here also - chan.register(selector, interestops, this); + chan.register(selector, interestOps, this); } } - int interestOps() { - return interestops; - } - /** * Returns a Stream containing only events that are - * registered with the given {@code interestop}. + * registered with the given {@code interestOps}. */ - Stream events(int interestop) { + Stream events(int interestOps) { return pending.stream() - .filter(ev -> (ev.interestOps() & interestop) != 0); + .filter(ev -> (ev.interestOps() & interestOps) != 0); } /** - * Removes any events with the given {@code interestop}, and if no + * Removes any events with the given {@code interestOps}, and if no * events remaining, cancels the associated SelectionKey. */ - void resetInterestOps(int interestop) { - int newops = 0; + void resetInterestOps(int interestOps) { + int newOps = 0; Iterator itr = pending.iterator(); while (itr.hasNext()) { AsyncEvent event = itr.next(); int evops = event.interestOps(); - if ((evops & interestop) != 0) { + if (event.repeating()) { + newOps |= evops; + continue; + } + if ((evops & interestOps) != 0) { itr.remove(); } else { - newops |= evops; + newOps |= evops; } } - interestops = newops; + this.interestOps = newOps; SelectionKey key = chan.keyFor(selector); - if (newops == 0) { + if (newOps == 0) { key.cancel(); } else { - key.interestOps(newops); + key.interestOps(newOps); } } } @@ -366,7 +384,8 @@ class HttpClientImpl extends HttpClient implements BufferHandler { /** * Creates a HttpRequest associated with this group. * - * @throws IllegalStateException if the group has been stopped + * @throws IllegalStateException + * if the group has been stopped */ @Override public HttpRequestBuilderImpl request() { @@ -376,7 +395,8 @@ class HttpClientImpl extends HttpClient implements BufferHandler { /** * Creates a HttpRequest associated with this group. * - * @throws IllegalStateException if the group has been stopped + * @throws IllegalStateException + * if the group has been stopped */ @Override public HttpRequestBuilderImpl request(URI uri) { @@ -444,16 +464,12 @@ class HttpClientImpl extends HttpClient implements BufferHandler { return version.equals(Version.HTTP_2); } - //void setHttp2NotSupported(String host) { - //http2NotSupported.put(host, false); - //} - - final void initFilters() { + private void initFilters() { addFilter(AuthenticationFilter.class); addFilter(RedirectFilter.class); } - final void addFilter(Class f) { + private void addFilter(Class f) { filters.addFilter(f); } @@ -479,14 +495,14 @@ class HttpClientImpl extends HttpClient implements BufferHandler { iter.previous(); break; } else if (!iter.hasNext()) { - event.delta = event.timeval - listval ; + event.delta = event.timeval - listval; } } iter.add(event); selmgr.wakeupSelector(); } - synchronized void signalTimeouts(long then) { + private synchronized void signalTimeouts(long then) { if (timeouts.isEmpty()) { return; } @@ -532,12 +548,12 @@ class HttpClientImpl extends HttpClient implements BufferHandler { // used for the connection window int getReceiveBufferSize() { return Utils.getIntegerNetProperty( - "sun.net.httpclient.connectionWindowSize", 256 * 1024 + "java.net.httpclient.connectionWindowSize", 256 * 1024 ); } // returns 0 meaning block forever, or a number of millis to block for - synchronized long getTimeoutValue() { + private synchronized long getTimeoutValue() { if (timeouts.isEmpty()) { return 0; } else { diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java b/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java index ea82531b469..21cecd6498e 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java @@ -23,9 +23,8 @@ */ package java.net.http; -import java.io.FileOutputStream; +import java.io.Closeable; import java.io.IOException; -import java.io.PrintStream; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; @@ -42,7 +41,17 @@ import javax.net.ssl.SSLParameters; * SSLConnection: TLS channel direct to server * SSLTunnelConnection: TLS channel via (CONNECT) proxy tunnel */ -abstract class HttpConnection implements BufferHandler { +abstract class HttpConnection implements BufferHandler, Closeable { + + protected final static ByteBuffer emptyBuf = Utils.EMPTY_BYTEBUFFER; + + enum Mode { + BLOCKING, + NON_BLOCKING, + ASYNC + } + + protected Mode mode; // address we are connected to. Could be a server or a proxy final InetSocketAddress address; @@ -52,6 +61,7 @@ abstract class HttpConnection implements BufferHandler { HttpConnection(InetSocketAddress address, HttpClientImpl client) { this.address = address; this.client = client; + this.buffer = emptyBuf; } /** @@ -68,7 +78,21 @@ abstract class HttpConnection implements BufferHandler { */ public static HttpConnection getConnection(InetSocketAddress addr, HttpRequestImpl request) { - return getConnectionImpl(addr, request); + return getConnectionImpl(addr, request, null); + } + + /** + * Called specifically to get an async connection for HTTP/2 over SSL. + * + * @param addr + * @param request + * @param http2 + * @return + */ + public static HttpConnection getConnection(InetSocketAddress addr, + HttpRequestImpl request, Http2Connection http2) { + + return getConnectionImpl(addr, request, http2); } public abstract void connect() throws IOException, InterruptedException; @@ -93,7 +117,7 @@ abstract class HttpConnection implements BufferHandler { // at beginning of response. ByteBuffer getRemaining() { ByteBuffer b = buffer; - buffer = null; + buffer = emptyBuf; return b; } @@ -123,17 +147,18 @@ abstract class HttpConnection implements BufferHandler { } private static HttpConnection getSSLConnection(InetSocketAddress addr, - InetSocketAddress proxy, - HttpRequestImpl request, - String[] alpn) { + InetSocketAddress proxy, HttpRequestImpl request, + String[] alpn, Http2Connection http2) { HttpClientImpl client = request.client(); if (proxy != null) { return new SSLTunnelConnection(addr, client, proxy, request.getAccessControlContext()); - } else { + } else if (http2 == null) { return new SSLConnection(addr, client, alpn); + } else { + return new AsyncSSLConnection(addr, client, alpn); } } @@ -142,7 +167,8 @@ abstract class HttpConnection implements BufferHandler { * none available. */ private static HttpConnection getConnectionImpl(InetSocketAddress addr, - HttpRequestImpl request) { + HttpRequestImpl request, Http2Connection http2) { + HttpConnection c; HttpClientImpl client = request.client(); InetSocketAddress proxy = request.proxy(); @@ -167,7 +193,7 @@ abstract class HttpConnection implements BufferHandler { if (c != null) { return c; } else { - return getSSLConnection(addr, proxy, request, alpn); + return getSSLConnection(addr, proxy, request, alpn, http2); } } } @@ -223,64 +249,16 @@ abstract class HttpConnection implements BufferHandler { return address; } - void configureBlocking(boolean mode) throws IOException { - channel().configureBlocking(mode); + synchronized void configureMode(Mode mode) throws IOException { + this.mode = mode; + if (mode == Mode.BLOCKING) + channel().configureBlocking(true); + else + channel().configureBlocking(false); } abstract ConnectionPool.CacheKey cacheKey(); - /* - static PrintStream ps; - - static { - try { - String propval = Utils.getNetProperty("java.net.httpclient.showData"); - if (propval != null && propval.equalsIgnoreCase("true")) { - ps = new PrintStream(new FileOutputStream("/tmp/httplog.txt"), false); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - synchronized final void debugPrint(String s, ByteBuffer b) { - ByteBuffer[] bufs = new ByteBuffer[1]; - bufs[0] = b; - debugPrint(s, bufs, 0, 1); - } - - synchronized final void debugPrint(String s, - ByteBuffer[] bufs, - int start, - int number) { - if (ps == null) { - return; - } - - ps.printf("\n%s:\n", s); - - for (int i=start; i 0x20 && c <= 0x7F) { - ps.printf("%c", (char)c); - } else { - ps.printf("0x%02x ", c); - } - } - } - ps.printf("\n---------------------\n"); - } - - */ - // overridden in SSL only SSLParameters sslParameters() { return null; @@ -296,7 +274,8 @@ abstract class HttpConnection implements BufferHandler { /** * Closes this connection, by returning the socket to its connection pool. */ - abstract void close(); + @Override + public abstract void close(); /** * Returns a ByteBuffer with data, or null if EOF. @@ -356,12 +335,17 @@ abstract class HttpConnection implements BufferHandler { } @Override - public final ByteBuffer getBuffer() { - return client.getBuffer(); + public final ByteBuffer getBuffer(int n) { + return client.getBuffer(n); } @Override public final void returnBuffer(ByteBuffer buffer) { client.returnBuffer(buffer); } + + @Override + public final void setMinBufferSize(int n) { + client.setMinBufferSize(n); + } } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java index 532625e65da..ee4122d22f8 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java @@ -24,44 +24,22 @@ package java.net.http; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.TreeMap; /** * Implementation of HttpHeaders. */ -class HttpHeadersImpl implements HttpHeaders1 { +class HttpHeadersImpl implements HttpHeaders { - private final HashMap> headers; - private boolean isUnmodifiable = false; + private final TreeMap> headers; public HttpHeadersImpl() { - headers = new HashMap<>(); - } - - /** - * Replace all List in headers with unmodifiable Lists. Call - * this only after all headers are added. The headers HashMap - * is wrapped with an unmodifiable HashMap in map() - */ - @Override - public void makeUnmodifiable() { - if (isUnmodifiable) - return; - - Set keys = new HashSet<>(headers.keySet()); - for (String key : keys) { - List values = headers.remove(key); - if (values != null) { - headers.put(key, Collections.unmodifiableList(values)); - } - } - isUnmodifiable = true; + headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); } @Override @@ -88,7 +66,7 @@ class HttpHeadersImpl implements HttpHeaders1 { public HttpHeadersImpl deepCopy() { HttpHeadersImpl h1 = new HttpHeadersImpl(); - HashMap> headers1 = h1.headers; + TreeMap> headers1 = h1.headers; Set keys = headers.keySet(); for (String key : keys) { List vals = headers.get(key); @@ -98,22 +76,13 @@ class HttpHeadersImpl implements HttpHeaders1 { return h1; } - private List getOrCreate(String name) { - List l = headers.get(name); - if (l == null) { - l = new LinkedList<>(); - headers.put(name, l); - } - return l; - } - void addHeader(String name, String value) { - List l = getOrCreate(name); - l.add(value); + headers.computeIfAbsent(name, k -> new LinkedList<>()) + .add(value); } void setHeader(String name, String value) { - List l = getOrCreate(name); + List l = headers.computeIfAbsent(name, k -> new LinkedList<>()); l.clear(); l.add(value); } @@ -122,7 +91,7 @@ class HttpHeadersImpl implements HttpHeaders1 { public Optional firstValueAsLong(String name) { List l = headers.get(name); if (l == null) { - return Optional.ofNullable(null); + return Optional.empty(); } else { String v = l.get(0); Long lv = Long.parseLong(v); @@ -133,4 +102,4 @@ class HttpHeadersImpl implements HttpHeaders1 { void clear() { headers.clear(); } -} +} \ No newline at end of file diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java index bc04ab3e921..d6d6604fd51 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java @@ -39,10 +39,11 @@ class HttpRequestBuilderImpl extends HttpRequest.Builder { private HttpClient.Version version; private final HttpClientImpl client; private ProxySelector proxy; - private long timeval = 0; + private long timeval; public HttpRequestBuilderImpl(HttpClientImpl client, URI uri) { this.client = client; + checkURI(uri); this.uri = uri; this.version = client.version(); this.userHeaders = new HttpHeadersImpl(); @@ -58,10 +59,17 @@ class HttpRequestBuilderImpl extends HttpRequest.Builder { @Override public HttpRequestBuilderImpl uri(URI uri) { Objects.requireNonNull(uri); + checkURI(uri); this.uri = uri; return this; } + private static void checkURI(URI uri) { + String scheme = uri.getScheme().toLowerCase(); + if (!scheme.equals("https") && !scheme.equals("http")) + throw new IllegalArgumentException("invalid URI scheme"); + } + @Override public HttpRequestBuilderImpl followRedirects(HttpClient.Redirect follow) { Objects.requireNonNull(follow); diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java index 10c0f16c6fd..dce47d43f72 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java @@ -30,16 +30,14 @@ import java.net.URI; import java.net.http.HttpClient.Version; import java.net.http.HttpResponse.MultiProcessor; import java.util.concurrent.CompletableFuture; -import java.net.SocketPermission; import java.security.AccessControlContext; import java.security.AccessController; -import java.util.Set; import static java.net.http.HttpRedirectImpl.getRedirects; import java.util.Locale; class HttpRequestImpl extends HttpRequest { - private final HttpHeadersImpl userHeaders; + private final ImmutableHeaders userHeaders; private final HttpHeadersImpl systemHeaders; private final URI uri; private InetSocketAddress authority; // only used when URI not specified @@ -56,6 +54,7 @@ class HttpRequestImpl extends HttpRequest { private boolean receiving; private AccessControlContext acc; private final long timeval; + private Stream.PushGroup pushGroup; public HttpRequestImpl(HttpClientImpl client, String method, @@ -63,8 +62,8 @@ class HttpRequestImpl extends HttpRequest { this.client = client; this.method = method == null? "GET" : method; this.userHeaders = builder.headers() == null ? - new HttpHeadersImpl() : builder.headers(); - dropDisallowedHeaders(); + new ImmutableHeaders() : + new ImmutableHeaders(builder.headers(), Utils.ALLOWED_HEADERS); this.followRedirects = getRedirects(builder.followRedirects() == null ? client.followRedirects() : builder.followRedirects()); this.systemHeaders = new HttpHeadersImpl(); @@ -90,15 +89,13 @@ class HttpRequestImpl extends HttpRequest { HttpRequestImpl other) { this.client = client; this.method = method == null? "GET" : method; - this.userHeaders = other.userHeaders == null ? - new HttpHeadersImpl() : other.userHeaders; - dropDisallowedHeaders(); + this.userHeaders = other.userHeaders; this.followRedirects = getRedirects(other.followRedirects() == null ? client.followRedirects() : other.followRedirects()); this.systemHeaders = other.systemHeaders; this.uri = uri; this.expectContinue = other.expectContinue; - this.secure = other.secure; + this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https"); this.requestProcessor = other.requestProcessor; this.proxy = other.proxy; this.version = other.version; @@ -115,7 +112,7 @@ class HttpRequestImpl extends HttpRequest { this.method = method; this.followRedirects = getRedirects(client.followRedirects()); this.systemHeaders = new HttpHeadersImpl(); - this.userHeaders = new HttpHeadersImpl(); + this.userHeaders = new ImmutableHeaders(); this.uri = null; this.proxy = null; this.requestProcessor = HttpRequest.noBody(); @@ -132,16 +129,52 @@ class HttpRequestImpl extends HttpRequest { return client; } + /** + * Creates a HttpRequestImpl from the given set of Headers and the associated + * "parent" request. Fields not taken from the headers are taken from the + * parent. + */ + static HttpRequestImpl createPushRequest(HttpRequestImpl parent, + HttpHeadersImpl headers) throws IOException { + + return new HttpRequestImpl(parent, headers); + } + + // only used for push requests + private HttpRequestImpl(HttpRequestImpl parent, HttpHeadersImpl headers) throws IOException { + this.method = headers.firstValue(":method") + .orElseThrow(() -> new IOException("No method in Push Promise")); + String path = headers.firstValue(":path") + .orElseThrow(() -> new IOException("No path in Push Promise")); + String scheme = headers.firstValue(":scheme") + .orElseThrow(() -> new IOException("No scheme in Push Promise")); + String authority = headers.firstValue(":authority") + .orElseThrow(() -> new IOException("No authority in Push Promise")); + StringBuilder sb = new StringBuilder(); + sb.append(scheme).append("://").append(authority).append(path); + this.uri = URI.create(sb.toString()); + + this.client = parent.client; + this.userHeaders = new ImmutableHeaders(headers, Utils.ALLOWED_HEADERS); + this.followRedirects = parent.followRedirects; + this.systemHeaders = parent.systemHeaders; + this.expectContinue = parent.expectContinue; + this.secure = parent.secure; + this.requestProcessor = parent.requestProcessor; + this.proxy = parent.proxy; + this.version = parent.version; + this.acc = parent.acc; + this.exchange = parent.exchange; + this.timeval = parent.timeval; + } @Override public String toString() { - return (uri == null ? "" : uri.toString()) + "/" + method + "(" - + hashCode() + ")"; + return (uri == null ? "" : uri.toString()) + " " + method; } @Override public HttpHeaders headers() { - userHeaders.makeUnmodifiable(); return userHeaders; } @@ -154,21 +187,6 @@ class HttpRequestImpl extends HttpRequest { systemHeaders.setHeader("HTTP2-Settings", h2client.getSettingsString()); } - private static final Set DISALLOWED_HEADERS_SET = Set.of( - "authorization", "connection", "cookie", "content-length", - "date", "expect", "from", "host", "origin", "proxy-authorization", - "referer", "user-agent", "upgrade", "via", "warning"); - - - // we silently drop headers that are disallowed - private void dropDisallowedHeaders() { - Set hdrnames = userHeaders.directMap().keySet(); - - hdrnames.removeIf((s) -> - DISALLOWED_HEADERS_SET.contains(s.toLowerCase()) - ); - } - private synchronized void receiving() { if (receiving) { throw new IllegalStateException("already receiving response"); @@ -176,6 +194,10 @@ class HttpRequestImpl extends HttpRequest { receiving = true; } + synchronized Stream.PushGroup pushGroup() { + return pushGroup; + } + /* * Response filters may result in a new HttpRequestImpl being created * (but still associated with the same API HttpRequest) and the process @@ -200,10 +222,25 @@ class HttpRequestImpl extends HttpRequest { .thenApply((r) -> (HttpResponse)r); } - public CompletableFuture - sendAsyncMulti(HttpResponse.MultiProcessor rspproc) { - // To change body of generated methods, choose Tools | Templates. - throw new UnsupportedOperationException("Not supported yet."); + + @SuppressWarnings("unchecked") + @Override + public synchronized CompletableFuture + multiResponseAsync(MultiProcessor rspproc) { + if (System.getSecurityManager() != null) { + acc = AccessController.getContext(); + } + this.pushGroup = new Stream.PushGroup<>(rspproc, this); + CompletableFuture cf = pushGroup.mainResponse(); + responseAsync() + .whenComplete((HttpResponse r, Throwable t) -> { + if (r != null) + cf.complete(r); + else + cf.completeExceptionally(t); + pushGroup.pushError(t); + }); + return (CompletableFuture)pushGroup.groupResult(); } @Override @@ -255,7 +292,7 @@ class HttpRequestImpl extends HttpRequest { @Override public URI uri() { return uri; } - HttpHeadersImpl getUserHeaders() { return userHeaders; } + HttpHeaders getUserHeaders() { return userHeaders; } HttpHeadersImpl getSystemHeaders() { return systemHeaders; } @@ -275,11 +312,4 @@ class HttpRequestImpl extends HttpRequest { } long timeval() { return timeval; } - - @Override - public CompletableFuture - multiResponseAsync(MultiProcessor rspproc) { - //To change body of generated methods, choose Tools | Templates. - throw new UnsupportedOperationException("Not supported yet."); - } } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java index c1ff5adb44e..eb7f7fa6930 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java @@ -200,8 +200,12 @@ public abstract class HttpResponse { if (n == -1) { throw new IOException("Bad Content-Disposition type"); } - String disposition = dispoHeader.substring(n + 9, - dispoHeader.lastIndexOf(';')); + int lastsemi = dispoHeader.lastIndexOf(';'); + String disposition; + if (lastsemi < n) + disposition = dispoHeader.substring(n + 9); + else + disposition = dispoHeader.substring(n + 9, lastsemi); file = Paths.get(directory.toString(), disposition); fc = FileChannel.open(file, openOptions); return null; @@ -727,11 +731,14 @@ public abstract class HttpResponse { } private CompletableFuture getBody(HttpRequest req, - CompletableFuture cf) { + CompletableFuture cf) { URI u = req.uri(); String path = u.getPath(); + if (path.startsWith("/")) + path = path.substring(1); + final String fpath = path; return cf.thenCompose((HttpResponse resp) -> { - return resp.bodyAsync(HttpResponse.asFile(destination.resolve(path))); + return resp.bodyAsync(HttpResponse.asFile(destination.resolve(fpath))); }); } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java index c71f53a04ea..10758d6db99 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java @@ -26,6 +26,7 @@ package java.net.http; import java.io.IOException; +import java.io.UncheckedIOException; import java.net.URI; import java.nio.ByteBuffer; import java.security.AccessControlContext; @@ -42,17 +43,18 @@ class HttpResponseImpl extends HttpResponse { int responseCode; Exchange exchange; HttpRequestImpl request; - HttpHeaders1 headers; - HttpHeaders1 trailers; + HttpHeaders headers; + HttpHeaders trailers; SSLParameters sslParameters; URI uri; HttpClient.Version version; AccessControlContext acc; RawChannel rawchan; HttpConnection connection; + final Stream stream; - public HttpResponseImpl(int responseCode, Exchange exch, HttpHeaders1 headers, - HttpHeaders1 trailers, SSLParameters sslParameters, + public HttpResponseImpl(int responseCode, Exchange exch, HttpHeaders headers, + HttpHeaders trailers, SSLParameters sslParameters, HttpClient.Version version, HttpConnection connection) { this.responseCode = responseCode; this.exchange = exch; @@ -63,6 +65,23 @@ class HttpResponseImpl extends HttpResponse { this.uri = request.uri(); this.version = version; this.connection = connection; + this.stream = null; + } + + // A response to a PUSH_PROMISE + public HttpResponseImpl(int responseCode, HttpRequestImpl pushRequest, + ImmutableHeaders headers, + Stream stream, SSLParameters sslParameters) { + this.responseCode = responseCode; + this.exchange = null; + this.request = pushRequest; + this.headers = headers; + this.trailers = null; + this.sslParameters = sslParameters; + this.uri = request.uri(); // TODO: take from headers + this.version = HttpClient.Version.HTTP_2; + this.connection = null; + this.stream = stream; } @Override @@ -77,26 +96,35 @@ class HttpResponseImpl extends HttpResponse { @Override public HttpHeaders headers() { - headers.makeUnmodifiable(); return headers; } @Override public HttpHeaders trailers() { - trailers.makeUnmodifiable(); return trailers; } @Override public T body(java.net.http.HttpResponse.BodyProcessor processor) { - return exchange.responseBody(processor); + try { + if (exchange != null) { + return exchange.responseBody(processor); + } else { + return stream.responseBody(processor); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } } @Override public CompletableFuture bodyAsync(java.net.http.HttpResponse.BodyProcessor processor) { acc = AccessController.getContext(); - return exchange.responseBodyAsync(processor); + if (exchange != null) + return exchange.responseBodyAsync(processor); + else + return stream.responseBodyAsync(processor); } @Override diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/ImmutableHeaders.java b/jdk/src/java.httpclient/share/classes/java/net/http/ImmutableHeaders.java new file mode 100644 index 00000000000..f1c3d50ff06 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/ImmutableHeaders.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.TreeMap; +import java.util.function.Predicate; + +/** + * Immutable HttpHeaders constructed from mutable HttpHeadersImpl. + */ + +class ImmutableHeaders implements HttpHeaders { + + private final Map> map; + + @SuppressWarnings("unchecked") + ImmutableHeaders() { + map = (Map>)Collections.EMPTY_MAP; + } + // TODO: fix lower case issue. Must be lc for http/2 compares ignoreCase for http/1 + ImmutableHeaders(HttpHeadersImpl h, Predicate keyAllowed) { + Map> src = h.directMap(); + Map> m = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + + src.forEach((key, value) -> { + if (keyAllowed.test(key)) + m.put(key, Collections.unmodifiableList(value)); + }); + map = Collections.unmodifiableMap(m); + } + + @Override + public Optional firstValue(String name) { + List l = map.get(name); + String v = l == null ? null : l.get(0); + return Optional.ofNullable(v); + } + + @Override + public Optional firstValueAsLong(String name) { + return firstValue(name).map((v -> Long.parseLong(v))); + } + + @Override + public List allValues(String name) { + return map.get(name); + } + + @Override + public Map> map() { + return map; + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Log.java b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java index 986a8fd1503..991edfefa6c 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Log.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java @@ -26,7 +26,9 @@ package java.net.http; import java.util.Locale; /** - * -Djava.net.HttpClient.log=errors,requests,headers,frames[:type:type2:..],content + * -Djava.net.HttpClient.log= + * errors,requests,headers, + * frames[:type:type2:..],content,ssl,trace * * Any of errors, requests, headers or content are optional. * @@ -47,6 +49,7 @@ abstract class Log implements System.Logger { public static final int CONTENT = 0x8; public static final int FRAMES = 0x10; public static final int SSL = 0x20; + public static final int TRACE = 0x40; static int logging; // Frame types: "control", "data", "window", "all" @@ -81,8 +84,11 @@ abstract class Log implements System.Logger { case "ssl": logging |= SSL; break; + case "trace": + logging |= TRACE; + break; case "all": - logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS; + logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS|TRACE; break; } if (val.startsWith("frames")) { @@ -130,6 +136,10 @@ abstract class Log implements System.Logger { return (logging & HEADERS) != 0; } + static boolean trace() { + return (logging & TRACE) != 0; + } + static boolean ssl() { return (logging & SSL) != 0; } @@ -138,9 +148,9 @@ abstract class Log implements System.Logger { return (logging & FRAMES) != 0; } - static void logError(String s) { + static void logError(String s, Object... s1) { if (errors()) - logger.log(Level.INFO, "ERROR: " + s); + logger.log(Level.INFO, "ERROR: " + s, s1); } static void logError(Throwable t) { @@ -150,24 +160,50 @@ abstract class Log implements System.Logger { } } - static void logSSL(String s) { + static void logSSL(String s, Object... s1) { if (ssl()) - logger.log(Level.INFO, "SSL: " + s); + logger.log(Level.INFO, "SSL: " + s, s1); } - static void logRequest(String s) { + static void logTrace(String s, Object... s1) { + if (trace()) { + String format = "TRACE: " + s; + logger.log(Level.INFO, format, s1); + } + } + + static void logRequest(String s, Object... s1) { if (requests()) - logger.log(Level.INFO, "REQUEST: " + s); + logger.log(Level.INFO, "REQUEST: " + s, s1); } - static void logResponse(String s) { + static void logResponse(String s, Object... s1) { if (requests()) - logger.log(Level.INFO, "RESPONSE: " + s); + logger.log(Level.INFO, "RESPONSE: " + s, s1); } - static void logHeaders(String s) { + static void logHeaders(String s, Object... s1) { if (headers()) - logger.log(Level.INFO, "HEADERS: " + s); + logger.log(Level.INFO, "HEADERS: " + s, s1); + } +// START HTTP2 + static boolean loggingFrame(Class clazz) { + if (frametypes == ALL) { + return true; + } + if (clazz == DataFrame.class) { + return (frametypes & DATA) != 0; + } else if (clazz == WindowUpdateFrame.class) { + return (frametypes & WINDOW_UPDATES) != 0; + } else { + return (frametypes & CONTROL) != 0; + } + } + + static void logFrames(Http2Frame f, String direction) { + if (frames() && loggingFrame(f.getClass())) { + logger.log(Level.INFO, "FRAME: " + direction + ": " + f.toString()); + } } // not instantiable diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java b/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java index 8a53565ae51..69e4bbbc7c4 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java @@ -54,7 +54,7 @@ class MultiExchange { final static int DEFAULT_MAX_ATTEMPTS = 5; final static int max_attempts = Utils.getIntegerNetProperty( - "sun.net.httpclient.redirects.retrylimit", DEFAULT_MAX_ATTEMPTS + "java.net.httpclient.redirects.retrylimit", DEFAULT_MAX_ATTEMPTS ); private final List filters; @@ -187,8 +187,7 @@ class MultiExchange { public CompletableFuture responseAsync(Void v) { CompletableFuture cf; if (++attempts > max_attempts) { - cf = new CompletableFuture<>(); - cf.completeExceptionally(new IOException("Too many retries")); + cf = CompletableFuture.failedFuture(new IOException("Too many retries")); } else { if (currentreq.timeval() != 0) { // set timer @@ -241,7 +240,6 @@ class MultiExchange { * completed exceptionally. */ private CompletableFuture getExceptionalCF(Throwable t) { - CompletableFuture error = new CompletableFuture<>(); if ((t instanceof CompletionException) || (t instanceof ExecutionException)) { if (t.getCause() != null) { t = t.getCause(); @@ -250,8 +248,7 @@ class MultiExchange { if (cancelled && t instanceof IOException) { t = new HttpTimeoutException("request timed out"); } - error.completeExceptionally(t); - return error; + return CompletableFuture.failedFuture(t); } T responseBody(HttpResponse.BodyProcessor processor) { diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/OutgoingHeaders.java b/jdk/src/java.httpclient/share/classes/java/net/http/OutgoingHeaders.java new file mode 100644 index 00000000000..6194022c0cc --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/OutgoingHeaders.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; + +/** + * Contains all parameters for outgoing headers. Is converted to + * HeadersFrame and ContinuationFrames by Http2Connection. + */ +class OutgoingHeaders extends Http2Frame { + + int streamDependency; + int weight; + boolean exclusive; + Stream stream; + + public static final int PRIORITY = 0x20; + + HttpHeaders user, system; + + OutgoingHeaders(HttpHeaders hdrs1, HttpHeaders hdrs2, Stream stream) { + this.user = hdrs2; + this.system = hdrs1; + this.stream = stream; + } + + public void setPriority(int streamDependency, boolean exclusive, int weight) { + this.streamDependency = streamDependency; + this.exclusive = exclusive; + this.weight = weight; + this.flags |= PRIORITY; + } + + public int getStreamDependency() { + return streamDependency; + } + + public int getWeight() { + return weight; + } + + public boolean getExclusive() { + return exclusive; + } + + public Stream getStream() { + return stream; + } + + public HttpHeaders getUserHeaders() { + return user; + } + + public HttpHeaders getSystemHeaders() { + return system; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + void computeLength() { + //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java b/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java index 5ffeaf6c961..b597b54bd92 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java @@ -43,4 +43,9 @@ final class Pair { static Pair pair(T first, U second) { return new Pair<>(first, second); } + + @Override + public String toString() { + return "(" + first + ", " + second + ")"; + } } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/PingFrame.java b/jdk/src/java.httpclient/share/classes/java/net/http/PingFrame.java new file mode 100644 index 00000000000..f9f202d86dc --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/PingFrame.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; +import java.nio.ByteBuffer; + +class PingFrame extends Http2Frame { + + PingFrame() { + type = TYPE; + } + + byte[] data; + + public final static int TYPE = 0x6; + + // Flags + public static final int ACK = 0x1; + + @Override + String flagAsString(int flag) { + switch (flag) { + case ACK: + return "ACK"; + } + return super.flagAsString(flag); + } + + public void setData(byte[] data) { + if (data.length != 8) { + throw new IllegalArgumentException("Ping data not 8 bytes"); + } + this.data = data; + } + + public byte[] getData() { + return data; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + if (length != 8) { + throw new IOException("Invalid Ping frame"); + } + data = bc.getBytes(8); + } + + @Override + void writeOutgoing(ByteBufferGenerator bg) { + if (data == null) { + data = new byte[] {0, 0, 0, 0, 0 ,0, 0, 0}; + } + super.writeOutgoing(bg); + ByteBuffer buf = bg.getBuffer(8); + buf.put(data); + } + + @Override + void computeLength() { + length = 8; + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java b/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java index e206f9204e2..eeadb35f7a0 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java @@ -31,20 +31,43 @@ import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; /** - * Plain raw TCP connection direct to destination + * Plain raw TCP connection direct to destination. 2 modes + * 1) Blocking used by http/1. In this case the connect is actually non + * blocking but the request is sent blocking. The first byte of a response + * is received non-blocking and the remainder of the response is received + * blocking + * 2) Non-blocking. In this case (for http/2) the connection is actually opened + * blocking but all reads and writes are done non-blocking under the + * control of a Http2Connection object. */ -class PlainHttpConnection extends HttpConnection { +class PlainHttpConnection extends HttpConnection implements AsyncConnection { protected SocketChannel chan; private volatile boolean connected; private boolean closed; + Consumer asyncReceiver; + Consumer errorReceiver; + Queue asyncOutputQ; + final Object reading = new Object(); + final Object writing = new Object(); - class ConnectEvent extends AsyncEvent implements AsyncEvent.Blocking { + @Override + public void startReading() { + try { + client.registerEvent(new ReadEvent()); + } catch (IOException e) { + shutdown(); + } + } + + class ConnectEvent extends AsyncEvent { CompletableFuture cf; ConnectEvent(CompletableFuture cf) { + super(AsyncEvent.BLOCKING); this.cf = cf; } @@ -112,14 +135,62 @@ class PlainHttpConnection extends HttpConnection { @Override long write(ByteBuffer[] buffers, int start, int number) throws IOException { - //debugPrint("Send", buffers, start, number); - return chan.write(buffers, start, number); + if (mode != Mode.ASYNC) + return chan.write(buffers, start, number); + // async + synchronized(writing) { + int qlen = asyncOutputQ.size(); + ByteBuffer[] bufs = Utils.reduce(buffers, start, number); + long n = Utils.remaining(bufs); + asyncOutputQ.putAll(bufs); + if (qlen == 0) + asyncOutput(); + return n; + } + } + + ByteBuffer asyncBuffer = null; + + void asyncOutput() { + synchronized (writing) { + try { + while (true) { + if (asyncBuffer == null) { + asyncBuffer = asyncOutputQ.poll(); + if (asyncBuffer == null) { + return; + } + } + if (!asyncBuffer.hasRemaining()) { + asyncBuffer = null; + continue; + } + int n = chan.write(asyncBuffer); + //System.err.printf("Written %d bytes to chan\n", n); + if (n == 0) { + client.registerEvent(new WriteEvent()); + return; + } + } + } catch (IOException e) { + shutdown(); + } + } } @Override long write(ByteBuffer buffer) throws IOException { - //debugPrint("Send", buffer); - return chan.write(buffer); + if (mode != Mode.ASYNC) + return chan.write(buffer); + // async + synchronized(writing) { + int qlen = asyncOutputQ.size(); + long n = buffer.remaining(); + asyncOutputQ.put(buffer); + if (qlen == 0) + asyncOutput(); + return n; + } } @Override @@ -131,7 +202,7 @@ class PlainHttpConnection extends HttpConnection { * Close this connection */ @Override - synchronized void close() { + public synchronized void close() { if (closed) return; closed = true; @@ -155,14 +226,49 @@ class PlainHttpConnection extends HttpConnection { return buf; } + void shutdown() { + close(); + errorReceiver.accept(new IOException("Connection aborted")); + } + + void asyncRead() { + synchronized (reading) { + try { + while (true) { + ByteBuffer buf = getBuffer(); + int n = chan.read(buf); + //System.err.printf("Read %d bytes from chan\n", n); + if (n == -1) { + throw new IOException(); + } + if (n == 0) { + returnBuffer(buf); + return; + } + buf.flip(); + asyncReceiver.accept(buf); + } + } catch (IOException e) { + shutdown(); + } + } + } + @Override protected int readImpl(ByteBuffer buf) throws IOException { int mark = buf.position(); - int n = chan.read(buf); + int n; + // FIXME: this hack works in conjunction with the corresponding change + // in java.net.http.RawChannel.registerEvent + if ((n = buffer.remaining()) != 0) { + buf.put(buffer); + } else { + n = chan.read(buf); + } if (n == -1) { return -1; } - Utils.flipToMark(buffer, mark); + Utils.flipToMark(buf, mark); String s = "Receive (" + n + " bytes) "; //debugPrint(s, buf); return n; @@ -178,10 +284,67 @@ class PlainHttpConnection extends HttpConnection { return connected; } - class ReceiveResponseEvent extends AsyncEvent implements AsyncEvent.Blocking { + // used for all output in HTTP/2 + class WriteEvent extends AsyncEvent { + WriteEvent() { + super(0); + } + + @Override + public SelectableChannel channel() { + return chan; + } + + @Override + public int interestOps() { + return SelectionKey.OP_WRITE; + } + + @Override + public void handle() { + asyncOutput(); + } + + @Override + public void abort() { + shutdown(); + } + } + + // used for all input in HTTP/2 + class ReadEvent extends AsyncEvent { + ReadEvent() { + super(AsyncEvent.REPEATING); // && !BLOCKING + } + + @Override + public SelectableChannel channel() { + return chan; + } + + @Override + public int interestOps() { + return SelectionKey.OP_READ; + } + + @Override + public void handle() { + asyncRead(); + } + + @Override + public void abort() { + shutdown(); + } + + } + + // used in blocking channels only + class ReceiveResponseEvent extends AsyncEvent { CompletableFuture cf; ReceiveResponseEvent(CompletableFuture cf) { + super(AsyncEvent.BLOCKING); this.cf = cf; } @Override @@ -215,6 +378,15 @@ class PlainHttpConnection extends HttpConnection { return false; } + @Override + public synchronized void setAsyncCallbacks(Consumer asyncReceiver, + Consumer errorReceiver) { + this.asyncReceiver = asyncReceiver; + this.errorReceiver = errorReceiver; + asyncOutputQ = new Queue<>(); + asyncOutputQ.registerPutCallback(this::asyncOutput); + } + @Override CompletableFuture whenReceivingResponse() { CompletableFuture cf = new CompletableFuture<>(); diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java b/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java index 2042baa2c4e..239bf3f8285 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java @@ -111,7 +111,7 @@ class PlainTunnelingConnection extends HttpConnection { } @Override - void close() { + public void close() { delegate.close(); connected = false; } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/PriorityFrame.java b/jdk/src/java.httpclient/share/classes/java/net/http/PriorityFrame.java new file mode 100644 index 00000000000..ab609e897ae --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/PriorityFrame.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; +import java.nio.ByteBuffer; + +class PriorityFrame extends Http2Frame { + + int streamDependency; + int weight; + boolean exclusive; + + public final static int TYPE = 0x2; + + PriorityFrame() { + type = TYPE; + } + + public PriorityFrame(int streamDependency, boolean exclusive, int weight) { + this.streamDependency = streamDependency; + this.exclusive = exclusive; + this.weight = weight; + this.type = TYPE; + } + + int streamDependency() { + return streamDependency; + } + + int weight() { + return weight; + } + + boolean exclusive() { + return exclusive; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + int x = bc.getInt(); + exclusive = (x & 0x80000000) != 0; + streamDependency = x & 0x7fffffff; + weight = bc.getByte(); + } + + @Override + void writeOutgoing(ByteBufferGenerator bg) { + super.writeOutgoing(bg); + ByteBuffer buf = bg.getBuffer(5); + int x = exclusive ? (1 << 31) + streamDependency : streamDependency; + buf.putInt(x); + buf.put((byte)weight); + } + + @Override + void computeLength() { + length = 5; + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/PushPromiseFrame.java b/jdk/src/java.httpclient/share/classes/java/net/http/PushPromiseFrame.java new file mode 100644 index 00000000000..6de21209dc5 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/PushPromiseFrame.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; +import java.nio.ByteBuffer; + +class PushPromiseFrame extends HeaderFrame { + + int padLength; + int promisedStream; + + PushPromiseFrame() { + type = TYPE; + } + + public static final int TYPE = 0x5; + + // Flags + public static final int END_HEADERS = 0x4; + public static final int PADDED = 0x8; + + @Override + public String toString() { + return super.toString() + " promisedStreamid: " + promisedStream + + " headerLength: " + headerLength; + } + + @Override + String flagAsString(int flag) { + switch (flag) { + case PADDED: + return "PADDED"; + case END_HEADERS: + return "END_HEADERS"; + } + return super.flagAsString(flag); + } + + public void setPadLength(int padLength) { + this.padLength = padLength; + flags |= PADDED; + } + + public void setPromisedStream(int stream) { + this.promisedStream = stream; + } + + public int getPromisedStream() { + return promisedStream; + } + + /** + */ + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + if ((flags & PADDED) != 0) { + padLength = bc.getByte(); + headerLength = length - (padLength + 5); + } else + headerLength = length - 4; + + promisedStream = bc.getInt() & 0x7fffffff; + headerBlocks = bc.getBuffers(headerLength); + } + + @Override + void computeLength() { + int len = 0; + if ((flags & PADDED) != 0) { + len += (1 + padLength); + } + len += (4 + headerLength); + this.length = len; + } + + @Override + void writeOutgoing(ByteBufferGenerator bg) { + super.writeOutgoing(bg); + ByteBuffer buf = bg.getBuffer(length); + if ((flags & PADDED) != 0) { + buf.put((byte)padLength); + } + buf.putInt(promisedStream); + for (int i=0; i implements Closeable { + + private final LinkedList q = new LinkedList<>(); + private volatile boolean closed = false; + private Runnable callback; + private boolean forceCallback; + private int waiters; // true if someone waiting + + synchronized void putAll(T[] objs) throws IOException { + if (closed) { + throw new IOException("stream closed"); + } + boolean wasEmpty = q.isEmpty(); + + for (T obj : objs) { + q.add(obj); + } + + if (waiters > 0) + notifyAll(); + + if (wasEmpty || forceCallback) { + forceCallback = false; + if (callback != null) { + callback.run(); + } + } + } + + synchronized int size() { + return q.size(); + } + + synchronized void put(T obj) throws IOException { + if (closed) { + throw new IOException("stream closed"); + } + + q.add(obj); + if (waiters > 0) + notifyAll(); + + if (q.size() == 1 || forceCallback) { + forceCallback = false; + if (callback != null) { + callback.run(); + } + } + } + + /** + * callback is invoked any time put is called where + * the Queue was empty. + */ + synchronized void registerPutCallback(Runnable callback) { + this.callback = callback; + if (callback != null && q.size() > 0) + callback.run(); + } + + @Override + public synchronized void close() { + closed = true; + notifyAll(); + } + + synchronized T take() throws IOException { + if (closed) { + throw new IOException("stream closed"); + } + try { + while (q.size() == 0) { + waiters++; + wait(); + waiters--; + } + return q.removeFirst(); + } catch (InterruptedException ex) { + throw new IOException(ex); + } + } + + public synchronized T poll() throws IOException { + if (closed) + throw new IOException("stream closed"); + + if (q.isEmpty()) + return null; + T res = q.removeFirst(); + return res; + } + + public synchronized T[] pollAll(T[] type) throws IOException { + T[] ret = q.toArray(type); + q.clear(); + return ret; + } + + public synchronized void pushback(T v) { + forceCallback = true; + q.addFirst(v); + } + + public synchronized void pushbackAll(T[] v) { + forceCallback = true; + for (int i=v.length-1; i>=0; i--) { + q.addFirst(v[i]); + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java b/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java index 9566eeb555c..536eda47afd 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java @@ -28,18 +28,18 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; import java.nio.channels.GatheringByteChannel; import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; -/** - * Used to implement WebSocket. Each RawChannel corresponds to - * a TCP connection (SocketChannel) but is connected to a Selector - * and an ExecutorService for invoking the send and receive callbacks - * Also includes SSL processing. - */ -class RawChannel implements ByteChannel, GatheringByteChannel { +// +// Used to implement WebSocket. Each RawChannel corresponds to a TCP connection +// (SocketChannel) but is connected to a Selector and an ExecutorService for +// invoking the send and receive callbacks. Also includes SSL processing. +// +final class RawChannel implements ByteChannel, GatheringByteChannel { private final HttpClientImpl client; private final HttpConnection connection; - private boolean closed; + private volatile boolean closed; private interface RawEvent { @@ -50,8 +50,6 @@ class RawChannel implements ByteChannel, GatheringByteChannel { void handle(); } - interface BlockingEvent extends RawEvent { } - interface NonBlockingEvent extends RawEvent { } RawChannel(HttpClientImpl client, HttpConnection connection) { @@ -64,39 +62,40 @@ class RawChannel implements ByteChannel, GatheringByteChannel { private final RawEvent re; RawAsyncEvent(RawEvent re) { + super(AsyncEvent.BLOCKING); // BLOCKING & !REPEATING this.re = re; } + RawAsyncEvent(RawEvent re, int flags) { + super(flags); + this.re = re; + } + + @Override public SelectableChannel channel() { return connection.channel(); } // must return the selector interest op flags OR'd + @Override public int interestOps() { return re.interestOps(); } // called when event occurs + @Override public void handle() { re.handle(); } - public void abort() {} + @Override + public void abort() { } } - private class BlockingRawAsyncEvent extends RawAsyncEvent - implements AsyncEvent.Blocking { - - BlockingRawAsyncEvent(RawEvent re) { - super(re); - } - } - - private class NonBlockingRawAsyncEvent extends RawAsyncEvent - implements AsyncEvent.NonBlocking { + private class NonBlockingRawAsyncEvent extends RawAsyncEvent { NonBlockingRawAsyncEvent(RawEvent re) { - super(re); + super(re, 0); // !BLOCKING & !REPEATING } } @@ -105,17 +104,24 @@ class RawChannel implements ByteChannel, GatheringByteChannel { * (i.e. register new event for each callback) */ public void registerEvent(RawEvent event) throws IOException { - if (event instanceof BlockingEvent) { - client.registerEvent(new BlockingRawAsyncEvent(event)); - } else if (event instanceof NonBlockingEvent) { - client.registerEvent(new NonBlockingRawAsyncEvent(event)); - } else { + if (!(event instanceof NonBlockingEvent)) { throw new InternalError(); } + if ((event.interestOps() & SelectionKey.OP_READ) != 0 + && connection.buffer.hasRemaining()) { + // FIXME: a hack to deal with leftovers from previous reads into an + // internal buffer (works in conjunction with change in + // java.net.http.PlainHttpConnection.readImpl(java.nio.ByteBuffer) + connection.channel().configureBlocking(false); + event.handle(); + } else { + client.registerEvent(new NonBlockingRawAsyncEvent(event)); + } } @Override public int read(ByteBuffer dst) throws IOException { + assert !connection.channel().isBlocking(); return connection.read(dst); } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java b/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java index 3c3be4d17c5..4bd18bd9c50 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java @@ -33,17 +33,19 @@ class RedirectFilter implements HeaderFilter { HttpRequestImpl requestImpl; HttpRequest request; HttpClientImpl client; + HttpClient.Redirect policy; String method; final static int DEFAULT_MAX_REDIRECTS = 5; URI uri; final static int max_redirects = Utils.getIntegerNetProperty( - "sun.net.httpclient.redirects.retrylimit", DEFAULT_MAX_REDIRECTS + "java.net.httpclient.redirects.retrylimit", DEFAULT_MAX_REDIRECTS ); @Override public void request(HttpRequestImpl r) throws IOException { this.request = r; + this.policy = request.followRedirects(); this.client = r.getClient(); this.method = r.method(); this.requestImpl = r; @@ -61,7 +63,7 @@ class RedirectFilter implements HeaderFilter { */ private HttpRequestImpl handleResponse(HttpResponseImpl r) { int rcode = r.statusCode(); - if (rcode == 200) { + if (rcode == 200 || policy == HttpClient.Redirect.NEVER) { return null; } if (rcode >= 300 && rcode <= 399) { @@ -79,6 +81,7 @@ class RedirectFilter implements HeaderFilter { private URI getRedirectedURI(HttpHeaders headers) { URI redirectedURI; + String ss = headers.firstValue("Location").orElse("Not present"); redirectedURI = headers.firstValue("Location") .map((s) -> URI.create(s)) .orElseThrow(() -> new UncheckedIOException( diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/ResetFrame.java b/jdk/src/java.httpclient/share/classes/java/net/http/ResetFrame.java new file mode 100644 index 00000000000..6e56586fb14 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResetFrame.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; +import java.nio.ByteBuffer; + +class ResetFrame extends ErrorFrame { + + public final static int TYPE = 0x3; + + // See ErrorFrame for error values + + ResetFrame() { + type = TYPE; + } + + public ResetFrame(int errorCode) { + this.errorCode = errorCode; + this.type = TYPE; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + errorCode = bc.getInt(); + } + + @Override + void writeOutgoing(ByteBufferGenerator bg) { + super.writeOutgoing(bg); + ByteBuffer buf = bg.getBuffer(4); + buf.putInt(errorCode); + } + + @Override + void computeLength() { + length = 4; + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java b/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java index b378e784c51..ad15bd735ff 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java @@ -48,7 +48,7 @@ import java.util.Set; * * This class is not thread-safe */ -class ResponseHeaders implements HttpHeaders1 { +class ResponseHeaders implements HttpHeaders { static final int DATA_SIZE = 16 * 1024; // initial space for headers static final int NUM_HEADERS = 50; // initial expected max number of headers @@ -368,10 +368,6 @@ class ResponseHeaders implements HttpHeaders1 { return Collections.unmodifiableList(l); } - @Override - public void makeUnmodifiable() { - } - // Delegates map to HashMap but converts keys to lower case static class HeaderMap implements Map> { diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java b/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java index 4b8cb3c0516..932c5b1c0f5 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java @@ -121,13 +121,8 @@ class SSLConnection extends HttpConnection { } @Override - void close() { - try { - //System.err.println ("Closing: " + this); - delegate.channel().close(); // TODO: proper close - } catch (IOException ex) { - Log.logError(ex.toString()); - } + public void close() { + Utils.close(delegate.channel()); } @Override diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java b/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java index fbc0674513c..27bad6659ad 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java @@ -29,13 +29,9 @@ import java.nio.channels.SocketChannel; import java.util.Arrays; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLEngineResult.Status; -import javax.net.ssl.SSLParameters; -import javax.net.ssl.SSLSession; +import javax.net.ssl.*; import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*; /** @@ -60,16 +56,18 @@ class SSLDelegate { engine.setUseClientMode(true); SSLParameters sslp = client.sslParameters().orElse(null); if (sslp == null) { - sslp = context.getDefaultSSLParameters(); + sslp = context.getSupportedSSLParameters(); } sslParameters = Utils.copySSLParameters(sslp); if (alpn != null) { sslParameters.setApplicationProtocols(alpn); Log.logSSL("Setting application protocols: " + Arrays.toString(alpn)); } else { - Log.logSSL("Warning no application protocols proposed!"); + Log.logSSL("No application protocols proposed"); } engine.setSSLParameters(sslParameters); + engine.setEnabledCipherSuites(sslp.getCipherSuites()); + engine.setEnabledProtocols(sslp.getProtocols()); wrapper = new EngineWrapper(chan, engine); this.chan = chan; this.client = client; @@ -268,7 +266,7 @@ class SSLDelegate { do { if (needData) { do { - x = chan.read (unwrap_src); + x = chan.read (unwrap_src); } while (x == 0); if (x == -1) { throw new IOException ("connection closed for reading"); @@ -440,6 +438,27 @@ class SSLDelegate { } } + static void printParams(SSLParameters p) { + System.out.println("SSLParameters:"); + if (p == null) { + System.out.println("Null params"); + return; + } + for (String cipher : p.getCipherSuites()) { + System.out.printf("cipher: %s\n", cipher); + } + for (String approto : p.getApplicationProtocols()) { + System.out.printf("application protocol: %s\n", approto); + } + for (String protocol : p.getProtocols()) { + System.out.printf("protocol: %s\n", protocol); + } + if (p.getServerNames() != null) + for (SNIServerName sname : p.getServerNames()) { + System.out.printf("server name: %s\n", sname.toString()); + } + } + String getSessionInfo() { StringBuilder sb = new StringBuilder(); String application = engine.getApplicationProtocol(); diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java b/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java index 8ec5786a687..fe8e766af77 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java @@ -130,12 +130,8 @@ class SSLTunnelConnection extends HttpConnection { } @Override - void close() { - try { - //System.err.println ("Closing: " + this); - delegate.channel().close(); // TODO: proper close - } catch (IOException ex) { - } + public void close() { + Utils.close(delegate.channel()); } @Override diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/SettingsFrame.java b/jdk/src/java.httpclient/share/classes/java/net/http/SettingsFrame.java new file mode 100644 index 00000000000..822a2564407 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/java/net/http/SettingsFrame.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 + */ + +package java.net.http; + +import java.io.IOException; +import java.nio.ByteBuffer; + +class SettingsFrame extends Http2Frame { + + int[] parameters; + + public static final int TYPE = 0x4; + + // Flags + public static final int ACK = 0x1; + + @Override + String flagAsString(int flag) { + switch (flag) { + case ACK: + return "ACK"; + } + return super.flagAsString(flag); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()) + .append(" Settings: "); + + for (int i = 0; i < MAX_PARAM; i++) { + if (parameters[i] != -1) { + sb.append(name(i)) + .append("=") + .append(Integer.toString(parameters[i])) + .append(' '); + } + } + return sb.toString(); + } + + // Parameters + public static final int HEADER_TABLE_SIZE = 0x1; + public static final int ENABLE_PUSH = 0x2; + public static final int MAX_CONCURRENT_STREAMS = 0x3; + public static final int INITIAL_WINDOW_SIZE = 0x4; + public static final int MAX_FRAME_SIZE = 0x5; + public static final int MAX_HEADER_LIST_SIZE = 0x6; + + private String name(int i) { + switch (i+1) { + case HEADER_TABLE_SIZE: + return "HEADER_TABLE_SIZE"; + case ENABLE_PUSH: + return "ENABLE_PUSH"; + case MAX_CONCURRENT_STREAMS: + return "MAX_CONCURRENT_STREAMS"; + case INITIAL_WINDOW_SIZE: + return "INITIAL_WINDOW_SIZE"; + case MAX_FRAME_SIZE: + return "MAX_FRAME_SIZE"; + case MAX_HEADER_LIST_SIZE: + return "MAX_HEADER_LIST_SIZE"; + } + return "unknown parameter"; + } + public static final int MAX_PARAM = 0x6; + + public SettingsFrame() { + type = TYPE; + parameters = new int [MAX_PARAM]; + for (int i=0; i < parameters.length; i++) { + parameters[i] = -1; + } + } + + public int getParameter(int paramID) { + if (paramID > MAX_PARAM) { + throw new IllegalArgumentException("illegal parameter"); + } + return parameters[paramID-1]; + } + + public SettingsFrame setParameter(int paramID, int value) { + if (paramID > MAX_PARAM) { + throw new IllegalArgumentException("illegal parameter"); + } + parameters[paramID-1] = value; + return this; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + if (length % 6 != 0) { + throw new IOException("Protocol error: invalid settings frame"); + } + int n = length / 6; + for (int i=0; i 0 || id <= MAX_PARAM) { + // a known parameter. Ignore otherwise + parameters[id-1] = val; + } + } + } + + @Override + void computeLength() { + length = 0; + for (int i : parameters) { + if (i != -1) { + length += 6; + } + } + } + + @Override + void writeOutgoing(ByteBufferGenerator bg) { + super.writeOutgoing(bg); + ByteBuffer buf = bg.getBuffer(length); + for (int i = 0; i < MAX_PARAM; i++) { + if (parameters[i] != -1) { + buf.putShort((short)(i+1)); + buf.putInt(parameters[i]); + } + } + } + + private static final int K = 1024; + + public static SettingsFrame getDefaultSettings() { + SettingsFrame f = new SettingsFrame(); + // TODO: check these values + f.setParameter(ENABLE_PUSH, 1); + f.setParameter(HEADER_TABLE_SIZE, 4 * K); + f.setParameter(MAX_CONCURRENT_STREAMS, 35); + f.setParameter(INITIAL_WINDOW_SIZE, 16 * K); + f.setParameter(MAX_FRAME_SIZE, 16 * K); + return f; + } +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java index 271e81c7a68..cea95c8f2f6 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * 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,78 +24,819 @@ package java.net.http; +import sun.net.httpclient.hpack.DecodingCallback; + import java.io.IOException; -import java.io.UncheckedIOException; import java.net.URI; import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; +import java.util.function.BiFunction; import java.util.function.LongConsumer; /** - * Http/2 Stream + * Http/2 Stream handling. + * + * REQUESTS + * + * sendHeadersOnly() -- assembles HEADERS frame and puts on connection outbound Q + * + * sendRequest() -- sendHeadersOnly() + sendBody() + * + * sendBody() -- in calling thread: obeys all flow control (so may block) + * obtains data from request body processor and places on connection + * outbound Q. + * + * sendBodyAsync() -- calls sendBody() in an executor thread. + * + * sendHeadersAsync() -- calls sendHeadersOnly() which does not block + * + * sendRequestAsync() -- calls sendRequest() in an executor thread + * + * RESPONSES + * + * Multiple responses can be received per request. Responses are queued up on + * a LinkedList of CF and the the first one on the list is completed + * with the next response + * + * getResponseAsync() -- queries list of response CFs and returns first one + * if one exists. Otherwise, creates one and adds it to list + * and returns it. Completion is achieved through the + * incoming() upcall from connection reader thread. + * + * getResponse() -- calls getResponseAsync() and waits for CF to complete + * + * responseBody() -- in calling thread: blocks for incoming DATA frames on + * stream inputQ. Obeys remote and local flow control so may block. + * Calls user response body processor with data buffers. + * + * responseBodyAsync() -- calls responseBody() in an executor thread. + * + * incoming() -- entry point called from connection reader thread. Frames are + * either handled immediately without blocking or for data frames + * placed on the stream's inputQ which is consumed by the stream's + * reader thread. + * + * PushedStream sub class + * ====================== + * Sending side methods are not used because the request comes from a PUSH_PROMISE + * frame sent by the server. When a PUSH_PROMISE is received the PushedStream + * is created. PushedStream does not use responseCF list as there can be only + * one response. The CF is created when the object created and when the response + * HEADERS frame is received the object is completed. */ class Stream extends ExchangeImpl { - void debugPrint() { - } + final Queue inputQ; + + volatile int streamid; + + long responseContentLen = -1; + long responseBytesProcessed = 0; + long requestContentLen; + + Http2Connection connection; + HttpClientImpl client; + final HttpRequestImpl request; + final DecodingCallback rspHeadersConsumer; + HttpHeadersImpl responseHeaders; + final HttpHeadersImpl requestHeaders; + final HttpHeadersImpl requestPseudoHeaders; + HttpResponse.BodyProcessor responseProcessor; + final HttpRequest.BodyProcessor requestProcessor; + HttpResponse response; + + // state flags + boolean requestSent, responseReceived; + + final FlowController userRequestFlowController = + new FlowController(); + final FlowController remoteRequestFlowController = + new FlowController(); + final FlowController responseFlowController = + new FlowController(); + + final ExecutorWrapper executor; @Override @SuppressWarnings("unchecked") CompletableFuture responseBodyAsync(HttpResponse.BodyProcessor processor) { - return null; - } - - Stream(HttpClientImpl client, Http2Connection connection, Exchange e) { - super(e); + this.responseProcessor = processor; + CompletableFuture cf; + try { + T body = processor.onResponseBodyStart( + responseContentLen, responseHeaders, + responseFlowController); // TODO: filter headers + if (body != null) { + cf = CompletableFuture.completedFuture(body); + receiveDataAsync(processor); + } else + cf = receiveDataAsync(processor); + } catch (IOException e) { + cf = CompletableFuture.failedFuture(e); + } + PushGroup pg = request.pushGroup(); + if (pg != null) { + // if an error occurs make sure it is recorded in the PushGroup + cf = cf.whenComplete((t,e) -> pg.pushError(e)); + } + return cf; } @Override - HttpResponseImpl getResponse() throws IOException { - return null; + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("streamid: ") + .append(streamid); + return sb.toString(); } - @Override - void sendRequest() throws IOException, InterruptedException { + // pushes entire response body into response processor + // blocking when required by local or remote flow control + void receiveData() throws IOException { + Http2Frame frame; + DataFrame df = null; + try { + do { + frame = inputQ.take(); + if (!(frame instanceof DataFrame)) { + assert false; + continue; + } + df = (DataFrame) frame; + int len = df.getDataLength(); + ByteBuffer[] buffers = df.getData(); + for (ByteBuffer b : buffers) { + responseFlowController.take(); + responseProcessor.onResponseBodyChunk(b); + } + sendWindowUpdate(len); + } while (!df.getFlag(DataFrame.END_STREAM)); + } catch (InterruptedException e) { + throw new IOException(e); + } } - @Override - void sendHeadersOnly() throws IOException, InterruptedException { + private CompletableFuture receiveDataAsync(HttpResponse.BodyProcessor processor) { + CompletableFuture cf = new CompletableFuture<>(); + executor.execute(() -> { + try { + receiveData(); + T body = processor.onResponseComplete(); + cf.complete(body); + responseReceived(); + } catch (Throwable t) { + cf.completeExceptionally(t); + } + }, null); + return cf; } - @Override - void sendBody() throws IOException, InterruptedException { - } - - @Override - CompletableFuture sendHeadersAsync() { - return null; - } - - @Override - CompletableFuture getResponseAsync(Void v) { - return null; + private void sendWindowUpdate(int increment) + throws IOException, InterruptedException { + if (increment == 0) + return; + LinkedList list = new LinkedList<>(); + WindowUpdateFrame frame = new WindowUpdateFrame(); + frame.streamid(streamid); + frame.setUpdate(increment); + list.add(frame); + frame = new WindowUpdateFrame(); + frame.streamid(0); + frame.setUpdate(increment); + list.add(frame); + connection.sendFrames(list); } @Override CompletableFuture sendBodyAsync() { - return null; + final CompletableFuture cf = new CompletableFuture<>(); + executor.execute(() -> { + try { + sendBodyImpl(); + cf.complete(null); + } catch (IOException | InterruptedException e) { + cf.completeExceptionally(e); + } + }, null); + return cf; + } + + @SuppressWarnings("unchecked") + Stream(HttpClientImpl client, Http2Connection connection, Exchange e) { + super(e); + this.client = client; + this.connection = connection; + this.request = e.request(); + this.requestProcessor = request.requestProcessor(); + responseHeaders = new HttpHeadersImpl(); + requestHeaders = new HttpHeadersImpl(); + rspHeadersConsumer = (name, value) -> { + responseHeaders.addHeader(name.toString(), value.toString()); + }; + this.executor = client.executorWrapper(); + //this.response_cf = new CompletableFuture(); + this.requestPseudoHeaders = new HttpHeadersImpl(); + // NEW + this.inputQ = new Queue<>(); + } + + @SuppressWarnings("unchecked") + Stream(HttpClientImpl client, Http2Connection connection, HttpRequestImpl req) { + super(null); + this.client = client; + this.connection = connection; + this.request = req; + this.requestProcessor = null; + responseHeaders = new HttpHeadersImpl(); + requestHeaders = new HttpHeadersImpl(); + rspHeadersConsumer = (name, value) -> { + responseHeaders.addHeader(name.toString(), value.toString()); + }; + this.executor = client.executorWrapper(); + //this.response_cf = new CompletableFuture(); + this.requestPseudoHeaders = new HttpHeadersImpl(); + // NEW + this.inputQ = new Queue<>(); + } + + /** + * Entry point from Http2Connection reader thread. + * + * Data frames will be removed by response body thread. + * + * @param frame + * @throws IOException + */ + void incoming(Http2Frame frame) throws IOException, InterruptedException { + if ((frame instanceof HeaderFrame) && ((HeaderFrame)frame).endHeaders()) { + // Complete headers accumulated. handle response. + // It's okay if there are multiple HeaderFrames. + handleResponse(); + } else if (frame instanceof DataFrame) { + inputQ.put(frame); + } else { + otherFrame(frame); + } + } + + void otherFrame(Http2Frame frame) throws IOException { + switch (frame.type()) { + case WindowUpdateFrame.TYPE: + incoming_windowUpdate((WindowUpdateFrame) frame); + break; + case ResetFrame.TYPE: + incoming_reset((ResetFrame) frame); + break; + case PriorityFrame.TYPE: + incoming_priority((PriorityFrame) frame); + break; + default: + String msg = "Unexpected frame: " + frame.toString(); + throw new IOException(msg); + } + } + + // The Hpack decoder decodes into one of these consumers of name,value pairs + + DecodingCallback rspHeadersConsumer() { + return rspHeadersConsumer; + } + + // create and return the HttpResponseImpl + protected void handleResponse() throws IOException { + HttpConnection c = connection.connection; // TODO: improve + long statusCode = responseHeaders + .firstValueAsLong(":status") + .orElseThrow(() -> new IOException("no statuscode in response")); + + this.response = new HttpResponseImpl((int)statusCode, exchange, responseHeaders, null, + c.sslParameters(), HttpClient.Version.HTTP_2, c); + this.responseContentLen = responseHeaders + .firstValueAsLong("content-length") + .orElse(-1L); + // different implementations for normal streams and pushed streams + completeResponse(response); + } + + void incoming_reset(ResetFrame frame) { + // TODO: implement reset + int error = frame.getErrorCode(); + IOException e = new IOException(ErrorFrame.stringForCode(error)); + completeResponseExceptionally(e); + throw new UnsupportedOperationException("Not implemented"); + } + + void incoming_priority(PriorityFrame frame) { + // TODO: implement priority + throw new UnsupportedOperationException("Not implemented"); + } + + void incoming_windowUpdate(WindowUpdateFrame frame) { + int amount = frame.getUpdate(); + if (amount > 0) + remoteRequestFlowController.accept(amount); + } + + void incoming_pushPromise(HttpRequestImpl pushReq, PushedStream pushStream) throws IOException { + if (Log.requests()) { + Log.logRequest("PUSH_PROMISE: " + pushReq.toString()); + } + PushGroup pushGroup = request.pushGroup(); + if (pushGroup == null) { + cancelImpl(new IllegalStateException("unexpected push promise")); + } + // get the handler and call it. + BiFunction,Boolean> ph = + pushGroup.pushHandler(); + + CompletableFuture pushCF = pushStream + .getResponseAsync(null) + .thenApply(r -> (HttpResponse)r); + boolean accept = ph.apply(pushReq, pushCF); + if (!accept) { + IOException ex = new IOException("Stream cancelled by user"); + cancelImpl(ex); + pushCF.completeExceptionally(ex); + } else { + pushStream.requestSent(); + pushGroup.addPush(); + } + } + + private OutgoingHeaders headerFrame(long contentLength) { + HttpHeadersImpl h = request.getSystemHeaders(); + if (contentLength > 0) { + h.setHeader("content-length", Long.toString(contentLength)); + } + setPseudoHeaderFields(); + OutgoingHeaders f = new OutgoingHeaders(h, request.getUserHeaders(), this); + if (contentLength == 0) { + f.setFlag(HeadersFrame.END_STREAM); + } + return f; + } + + private void setPseudoHeaderFields() { + HttpHeadersImpl hdrs = requestPseudoHeaders; + String method = request.method(); + hdrs.setHeader(":method", method); + URI uri = request.uri(); + hdrs.setHeader(":scheme", uri.getScheme()); + // TODO: userinfo deprecated. Needs to be removed + hdrs.setHeader(":authority", uri.getAuthority()); + // TODO: ensure header names beginning with : not in user headers + String query = uri.getQuery(); + String path = uri.getPath(); + if (path == null) { + if (method.equalsIgnoreCase("OPTIONS")) { + path = "*"; + } else { + path = "/"; + } + } + if (query != null) { + path += "?" + query; + } + hdrs.setHeader(":path", path); + } + + HttpHeadersImpl getRequestPseudoHeaders() { + return requestPseudoHeaders; + } + + @Override + HttpResponseImpl getResponse() throws IOException { + try { + return getResponseAsync(null).join(); + } catch (Throwable e) { + Throwable t = e.getCause(); + if (t instanceof IOException) { + throw (IOException)t; + } + throw e; + } + } + + @Override + void sendRequest() throws IOException, InterruptedException { + sendHeadersOnly(); + sendBody(); + } + + /** + * A simple general purpose blocking flow controller + */ + class FlowController implements LongConsumer { + int permits; + + FlowController() { + this.permits = 0; + } + + @Override + public synchronized void accept(long n) { + if (n < 1) { + throw new InternalError("FlowController.accept called with " + n); + } + if (permits == 0) { + permits += n; + notifyAll(); + } else { + permits += n; + } + } + + public synchronized void take() throws InterruptedException { + take(1); + } + + public synchronized void take(int amount) throws InterruptedException { + assert permits >= 0; + while (permits < amount) { + int n = Math.min(amount, permits); + permits -= n; + amount -= n; + if (amount > 0) + wait(); + } + } + } + + @Override + void sendHeadersOnly() throws IOException, InterruptedException { + if (Log.requests() && request != null) { + Log.logRequest(request.toString()); + } + requestContentLen = requestProcessor.onRequestStart(request, userRequestFlowController); + OutgoingHeaders f = headerFrame(requestContentLen); + connection.sendFrame(f); + } + + @Override + void sendBody() throws IOException, InterruptedException { + sendBodyImpl(); + } + + void registerStream(int id) { + this.streamid = id; + connection.putStream(this, streamid); + } + + DataFrame getDataFrame() throws IOException, InterruptedException { + userRequestFlowController.take(); + int maxpayloadLen = connection.getMaxSendFrameSize() - 9; + ByteBuffer buffer = connection.getBuffer(); + buffer.limit(maxpayloadLen); + boolean complete = requestProcessor.onRequestBodyChunk(buffer); + buffer.flip(); + int amount = buffer.remaining(); + // wait for flow control if necessary. Following method will block + // until after headers frame is sent, so correct streamid is set. + remoteRequestFlowController.take(amount); + connection.obtainSendWindow(amount); + + DataFrame df = new DataFrame(); + df.streamid(streamid); + if (complete) { + df.setFlag(DataFrame.END_STREAM); + } + df.setData(buffer); + df.computeLength(); + return df; + } + + + @Override + CompletableFuture sendHeadersAsync() { + try { + sendHeadersOnly(); + return CompletableFuture.completedFuture(null); + } catch (IOException | InterruptedException ex) { + return CompletableFuture.failedFuture(ex); + } + } + + /** + * A List of responses relating to this stream. Normally there is only + * one response, but intermediate responses like 100 are allowed + * and must be passed up to higher level before continuing. Deals with races + * such as if responses are returned before the CFs get created by + * getResponseAsync() + */ + + final List> response_cfs = new LinkedList<>(); + + @Override + CompletableFuture getResponseAsync(Void v) { + CompletableFuture cf; + synchronized (response_cfs) { + if (!response_cfs.isEmpty()) { + cf = response_cfs.remove(0); + } else { + cf = new CompletableFuture<>(); + response_cfs.add(cf); + } + } + PushGroup pg = request.pushGroup(); + if (pg != null) { + // if an error occurs make sure it is recorded in the PushGroup + cf = cf.whenComplete((t,e) -> pg.pushError(e)); + } + return cf; + } + + /** + * Completes the first uncompleted CF on list, and removes it. If there is no + * uncompleted CF then creates one (completes it) and adds to list + */ + void completeResponse(HttpResponse r) { + HttpResponseImpl resp = (HttpResponseImpl)r; + synchronized (response_cfs) { + for (CompletableFuture cf : response_cfs) { + if (!cf.isDone()) { + cf.complete(resp); + response_cfs.remove(cf); + //responseHeaders = new HttpHeadersImpl(); // for any following header blocks + return; + } else + System.err.println("Stream: " + this + " ALREADY DONE"); + } + response_cfs.add(CompletableFuture.completedFuture(resp)); + //responseHeaders = new HttpHeadersImpl(); // for any following header blocks + } + } + + // methods to update state and remove stream when finished + + synchronized void requestSent() { + requestSent = true; + if (responseReceived) + connection.deleteStream(this); + } + + synchronized void responseReceived() { + responseReceived = true; + if (requestSent) + connection.deleteStream(this); + PushGroup pg = request.pushGroup(); + if (pg != null) + pg.noMorePushes(); + } + + /** + * same as above but for errors + * + * @param t + */ + void completeResponseExceptionally(Throwable t) { + synchronized (response_cfs) { + for (CompletableFuture cf : response_cfs) { + if (!cf.isDone()) { + cf.completeExceptionally(t); + response_cfs.remove(cf); + return; + } + } + response_cfs.add(CompletableFuture.failedFuture(t)); + } + } + + void sendBodyImpl() throws IOException, InterruptedException { + if (requestContentLen == 0) { + // no body + return; + } + DataFrame df; + do { + df = getDataFrame(); + // TODO: check accumulated content length (if not checked below) + connection.sendFrame(df); + } while (!df.getFlag(DataFrame.END_STREAM)); + requestSent(); } @Override void cancel() { + cancelImpl(new Exception("Cancelled")); } + void cancelImpl(Throwable e) { + Log.logTrace("cancelling stream: {0}\n", e.toString()); + inputQ.close(); + try { + connection.resetStream(streamid, ResetFrame.CANCEL); + } catch (IOException | InterruptedException ex) { + Log.logError(ex); + } + } + @Override CompletableFuture sendRequestAsync() { - return null; + CompletableFuture cf = new CompletableFuture<>(); + executor.execute(() -> { + try { + sendRequest(); + cf.complete(null); + } catch (IOException |InterruptedException e) { + cf.completeExceptionally(e); + } + }, null); + return cf; } @Override T responseBody(HttpResponse.BodyProcessor processor) throws IOException { - return null; + this.responseProcessor = processor; + T body = processor.onResponseBodyStart( + responseContentLen, responseHeaders, + responseFlowController); // TODO: filter headers + if (body == null) { + receiveData(); + return processor.onResponseComplete(); + } else + receiveDataAsync(processor); + responseReceived(); + return body; + } + + // called from Http2Connection reader thread + synchronized void updateOutgoingWindow(int update) { + remoteRequestFlowController.accept(update); + } + + void close(String msg) { + cancel(); + } + + static class PushedStream extends Stream { + final PushGroup pushGroup; + final private Stream parent; // used by server push streams + // push streams need the response CF allocated up front as it is + // given directly to user via the multi handler callback function. + final CompletableFuture pushCF; + final HttpRequestImpl pushReq; + + PushedStream(PushGroup pushGroup, HttpClientImpl client, + Http2Connection connection, Stream parent, + HttpRequestImpl pushReq) { + super(client, connection, pushReq); + this.pushGroup = pushGroup; + this.pushReq = pushReq; + this.pushCF = new CompletableFuture<>(); + this.parent = parent; + } + + // Following methods call the super class but in case of + // error record it in the PushGroup. The error method is called + // with a null value when no error occurred (is a no-op) + @Override + CompletableFuture sendBodyAsync() { + return super.sendBodyAsync() + .whenComplete((v, t) -> pushGroup.pushError(t)); + } + + @Override + CompletableFuture sendHeadersAsync() { + return super.sendHeadersAsync() + .whenComplete((v, t) -> pushGroup.pushError(t)); + } + + @Override + CompletableFuture sendRequestAsync() { + return super.sendRequestAsync() + .whenComplete((v, t) -> pushGroup.pushError(t)); + } + + @Override + CompletableFuture getResponseAsync(Void vo) { + return pushCF.whenComplete((v, t) -> pushGroup.pushError(t)); + } + + @Override + CompletableFuture responseBodyAsync(HttpResponse.BodyProcessor processor) { + return super.responseBodyAsync(processor) + .whenComplete((v, t) -> pushGroup.pushError(t)); + } + + @Override + void completeResponse(HttpResponse r) { + HttpResponseImpl resp = (HttpResponseImpl)r; + Utils.logResponse(resp); + pushCF.complete(resp); + } + + @Override + void completeResponseExceptionally(Throwable t) { + pushCF.completeExceptionally(t); + } + + @Override + synchronized void responseReceived() { + super.responseReceived(); + pushGroup.pushCompleted(); + } + + // create and return the PushResponseImpl + @Override + protected void handleResponse() { + HttpConnection c = connection.connection; // TODO: improve + long statusCode = responseHeaders + .firstValueAsLong(":status") + .orElse(-1L); + + if (statusCode == -1L) + completeResponseExceptionally(new IOException("No status code")); + ImmutableHeaders h = new ImmutableHeaders(responseHeaders, Utils.ALL_HEADERS); + this.response = new HttpResponseImpl((int)statusCode, pushReq, h, this, + c.sslParameters()); + this.responseContentLen = responseHeaders + .firstValueAsLong("content-length") + .orElse(-1L); + // different implementations for normal streams and pushed streams + completeResponse(response); + } + } + + /** + * One PushGroup object is associated with the parent Stream of + * the pushed Streams. This keeps track of all common state associated + * with the pushes. + */ + static class PushGroup { + // the overall completion object, completed when all pushes are done. + final CompletableFuture resultCF; + Throwable error; // any exception that occured during pushes + + // CF for main response + final CompletableFuture mainResponse; + + // user's processor object + final HttpResponse.MultiProcessor multiProcessor; + + // per push handler function provided by processor + final private BiFunction, + Boolean> pushHandler; + int numberOfPushes; + int remainingPushes; + boolean noMorePushes = false; + + PushGroup(HttpResponse.MultiProcessor multiProcessor, HttpRequestImpl req) { + this.resultCF = new CompletableFuture<>(); + this.mainResponse = new CompletableFuture<>(); + this.multiProcessor = multiProcessor; + this.pushHandler = multiProcessor.onStart(req, mainResponse); + } + + CompletableFuture groupResult() { + return resultCF; + } + + CompletableFuture mainResponse() { + return mainResponse; + } + + private BiFunction, Boolean> pushHandler() + { + return pushHandler; + } + + synchronized void addPush() { + numberOfPushes++; + remainingPushes++; + } + + synchronized int numberOfPushes() { + return numberOfPushes; + } + // This is called when the main body response completes because it means + // no more PUSH_PROMISEs are possible + synchronized void noMorePushes() { + noMorePushes = true; + checkIfCompleted(); + } + + synchronized void pushCompleted() { + remainingPushes--; + checkIfCompleted(); + } + + synchronized void checkIfCompleted() { + if (remainingPushes == 0 && error == null && noMorePushes) { + T overallResult = multiProcessor.onComplete(); + resultCF.complete(overallResult); + } + } + + synchronized void pushError(Throwable t) { + if (t == null) + return; + this.error = t; + resultCF.completeExceptionally(t); + } } } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java b/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java index a201a23f4bd..d16248d4b6b 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java @@ -21,28 +21,37 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any */ - package java.net.http; +import sun.net.NetProperties; + +import javax.net.ssl.SSLParameters; import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.IOException; import java.io.PrintStream; import java.io.UnsupportedEncodingException; +import java.net.InetSocketAddress; import java.net.NetPermission; import java.net.URI; import java.net.URLPermission; +import java.nio.Buffer; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; -import javax.net.ssl.SSLParameters; -import sun.net.NetProperties; +import java.util.concurrent.CompletableFuture; +import java.util.function.LongBinaryOperator; +import java.util.function.Predicate; /** * Miscellaneous utilities */ -class Utils { +final class Utils { /** * Allocated buffer size. Must never be higher than 16K. But can be lower @@ -51,7 +60,59 @@ class Utils { */ public static final int BUFSIZE = 16 * 1024; - /** Validates a RFC7230 token */ + private static final Set DISALLOWED_HEADERS_SET = Set.of( + "authorization", "connection", "cookie", "content-length", + "date", "expect", "from", "host", "origin", "proxy-authorization", + "referer", "user-agent", "upgrade", "via", "warning"); + + static final Predicate + ALLOWED_HEADERS = header -> !Utils.DISALLOWED_HEADERS_SET.contains(header); + + static final Predicate + ALL_HEADERS = header -> true; + + static InetSocketAddress getAddress(HttpRequestImpl req) { + URI uri = req.uri(); + if (uri == null) { + return req.authority(); + } + int port = uri.getPort(); + if (port == -1) { + if (uri.getScheme().equalsIgnoreCase("https")) { + port = 443; + } else { + port = 80; + } + } + String host = uri.getHost(); + if (req.proxy() == null) { + return new InetSocketAddress(host, port); + } else { + return InetSocketAddress.createUnresolved(host, port); + } + } + + /** + * Puts position to limit and limit to capacity so we can resume reading + * into this buffer, but if required > 0 then limit may be reduced so that + * no more than required bytes are read next time. + */ + static void resumeChannelRead(ByteBuffer buf, int required) { + int limit = buf.limit(); + buf.position(limit); + int capacity = buf.capacity() - limit; + if (required > 0 && required < capacity) { + buf.limit(limit + required); + } else { + buf.limit(buf.capacity()); + } + } + + private Utils() { } + + /** + * Validates a RFC7230 token + */ static void validateToken(String token, String errormsg) { int length = token.length(); for (int i = 0; i < length; i++) { @@ -69,7 +130,7 @@ class Utils { } /** - * Return sthe security permission required for the given details. + * Returns the security permission required for the given details. * If method is CONNECT, then uri must be of form "scheme://host:port" */ static URLPermission getPermission(URI uri, @@ -117,13 +178,13 @@ class Utils { } static int getIntegerNetProperty(String name, int defaultValue) { - return AccessController.doPrivileged((PrivilegedAction)() -> - NetProperties.getInteger(name, defaultValue) ); + return AccessController.doPrivileged((PrivilegedAction) () -> + NetProperties.getInteger(name, defaultValue)); } static String getNetProperty(String name) { - return AccessController.doPrivileged((PrivilegedAction)() -> - NetProperties.get(name) ); + return AccessController.doPrivileged((PrivilegedAction) () -> + NetProperties.get(name)); } static SSLParameters copySSLParameters(SSLParameters p) { @@ -134,7 +195,9 @@ class Utils { p1.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm()); p1.setMaximumPacketSize(p.getMaximumPacketSize()); p1.setNeedClientAuth(p.getNeedClientAuth()); - p1.setProtocols(p.getProtocols().clone()); + String[] protocols = p.getProtocols(); + if (protocols != null) + p1.setProtocols(protocols.clone()); p1.setSNIMatchers(p.getSNIMatchers()); p1.setServerNames(p.getServerNames()); p1.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder()); @@ -142,33 +205,14 @@ class Utils { return p1; } - - /** Resumes reading into the given buffer. */ - static void unflip(ByteBuffer buf) { - buf.position(buf.limit()); - buf.limit(buf.capacity()); - } - /** * Set limit to position, and position to mark. - * - * - * @param buffer - * @param mark */ static void flipToMark(ByteBuffer buffer, int mark) { buffer.limit(buffer.position()); buffer.position(mark); } - /** Compact and leave ready for reading. */ - static void compact(List buffers) { - for (ByteBuffer b : buffers) { - b.compact(); - b.flip(); - } - } - static String stackTrace(Throwable t) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); String s = null; @@ -182,8 +226,10 @@ class Utils { return s; } - /** Copies as much of src to dst as possible. */ - static void copy (ByteBuffer src, ByteBuffer dst) { + /** + * Copies as much of src to dst as possible. + */ + static void copy(ByteBuffer src, ByteBuffer dst) { int srcLen = src.remaining(); int dstLen = dst.remaining(); if (srcLen > dstLen) { @@ -204,18 +250,101 @@ class Utils { return dst; } - static String combine(String[] s) { - StringBuilder sb = new StringBuilder(); - sb.append('['); - boolean first = true; - for (String s1 : s) { - if (!first) { - sb.append(", "); - first = false; - } - sb.append(s1); - } - sb.append(']'); - return sb.toString(); + // + // Helps to trim long names (packages, nested/inner types) in logs/toString + // + static String toStringSimple(Object o) { + return o.getClass().getSimpleName() + "@" + + Integer.toHexString(System.identityHashCode(o)); } + + // + // 1. It adds a number of remaining bytes; + // 2. Standard Buffer-type toString for CharBuffer (since it adheres to the + // contract of java.lang.CharSequence.toString() which is both not too + // useful and not too private) + // + static String toString(Buffer b) { + return toStringSimple(b) + + "[pos=" + b.position() + + " lim=" + b.limit() + + " cap=" + b.capacity() + + " rem=" + b.remaining() + "]"; + } + + static String toString(CharSequence s) { + return s == null + ? "null" + : toStringSimple(s) + "[len=" + s.length() + "]"; + } + + static String dump(Object... objects) { + return Arrays.toString(objects); + } + + static final System.Logger logger = System.getLogger("java.net.http.WebSocket"); + + static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocate(0); + + static String webSocketSpecViolation(String section, String detail) { + return "RFC 6455 " + section + " " + detail; + } + + static void logResponse(HttpResponseImpl r) { + if (!Log.requests()) { + return; + } + StringBuilder sb = new StringBuilder(); + String method = r.request().method(); + URI uri = r.uri(); + String uristring = uri == null ? "" : uri.toString(); + sb.append('(').append(method).append(" ").append(uristring).append(") ").append(Integer.toString(r.statusCode())); + Log.logResponse(sb.toString()); + } + + static int remaining(ByteBuffer[] bufs) { + int remain = 0; + for (ByteBuffer buf : bufs) + remain += buf.remaining(); + return remain; + } + + // assumes buffer was written into starting at position zero + static void unflip(ByteBuffer buf) { + buf.position(buf.limit()); + buf.limit(buf.capacity()); + } + + static void close(Closeable... chans) { + for (Closeable chan : chans) { + System.err.println("Closing " + chan); + try { + chan.close(); + } catch (IOException e) { + } + } + } + + static ByteBuffer[] reduce(ByteBuffer[] bufs, int start, int number) { + if (start == 0 && number == bufs.length) + return bufs; + ByteBuffer[] nbufs = new ByteBuffer[number]; + int j = 0; + for (int i=start; iHigh level HTTP API - * This provides a high-level client interface to HTTP (versions 1.1 and 2). - * Synchronous and asynchronous (via - * {@link java.util.concurrent.CompletableFuture}) modes are provided. The main - * classes defined are: + *

      High level HTTP and WebSocket API

      + * This provides a high-level client interfaces to HTTP (versions 1.1 and 2) + * and WebSocket. Synchronous and asynchronous (via {@link + * java.util.concurrent.CompletableFuture}) modes are provided for HTTP. + * WebSocket works in asynchronous mode only. The main types defined are: *
        *
      • {@link java.net.http.HttpClient}
      • *
      • {@link java.net.http.HttpRequest}
      • diff --git a/jdk/test/java/net/httpclient/APIErrors.java b/jdk/test/java/net/httpclient/APIErrors.java index 845c665088a..193cfa7f2e8 100644 --- a/jdk/test/java/net/httpclient/APIErrors.java +++ b/jdk/test/java/net/httpclient/APIErrors.java @@ -26,6 +26,7 @@ * @bug 8087112 * @library /lib/testlibrary/ * @build jdk.testlibrary.SimpleSSLContext ProxyServer + * @build TestKit * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java * @run main/othervm APIErrors @@ -73,26 +74,6 @@ public class APIErrors { } } - static void reject(Runnable r, Class extype) { - try { - r.run(); - throw new RuntimeException("Expected: " + extype); - } catch (Throwable t) { - if (!extype.isAssignableFrom(t.getClass())) { - throw new RuntimeException("Wrong exception type: " + extype + " / " - +t.getClass()); - } - } - } - - static void accept(Runnable r) { - try { - r.run(); - } catch (Throwable t) { - throw new RuntimeException("Unexpected exception: " + t); - } - } - static void checkNonNull(Supplier r) { if (r.get() == null) throw new RuntimeException("Unexpected null return:"); @@ -108,12 +89,14 @@ public class APIErrors { System.out.println("Test 1"); HttpClient.Builder cb = HttpClient.create(); InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 5000); - reject(() -> { cb.priority(-1);}, IllegalArgumentException.class); - reject(() -> { cb.priority(500);}, IllegalArgumentException.class); - accept(() -> { cb.priority(1);}); - accept(() -> { cb.priority(255);}); - - accept(() -> {clients.add(cb.build()); clients.add(cb.build());}); + TestKit.assertThrows(IllegalArgumentException.class, () -> cb.priority(-1)); + TestKit.assertThrows(IllegalArgumentException.class, () -> cb.priority(500)); + TestKit.assertNotThrows(() -> cb.priority(1)); + TestKit.assertNotThrows(() -> cb.priority(255)); + TestKit.assertNotThrows(() -> { + clients.add(cb.build()); + clients.add(cb.build()); + }); } static void test2() throws Exception { @@ -139,7 +122,7 @@ public class APIErrors { static void test3() throws Exception { System.out.println("Test 3"); - reject(()-> { + TestKit.assertThrows(IllegalStateException.class, ()-> { try { HttpRequest r1 = request(); HttpResponse resp = r1.response(); @@ -147,9 +130,9 @@ public class APIErrors { } catch (IOException |InterruptedException e) { throw new RuntimeException(e); } - }, IllegalStateException.class); + }); - reject(()-> { + TestKit.assertThrows(IllegalStateException.class, ()-> { try { HttpRequest r1 = request(); HttpResponse resp = r1.response(); @@ -157,8 +140,8 @@ public class APIErrors { } catch (IOException |InterruptedException | ExecutionException e) { throw new RuntimeException(e); } - }, IllegalStateException.class); - reject(()-> { + }); + TestKit.assertThrows(IllegalStateException.class, ()-> { try { HttpRequest r1 = request(); HttpResponse resp1 = r1.responseAsync().get(); @@ -166,7 +149,7 @@ public class APIErrors { } catch (IOException |InterruptedException | ExecutionException e) { throw new RuntimeException(e); } - }, IllegalStateException.class); + }); } static class Auth extends java.net.Authenticator { diff --git a/jdk/test/java/net/httpclient/EchoHandler.java b/jdk/test/java/net/httpclient/EchoHandler.java new file mode 100644 index 00000000000..ea14d2330fa --- /dev/null +++ b/jdk/test/java/net/httpclient/EchoHandler.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.sun.net.httpserver.*; +import java.net.*; +import java.net.http.*; +import java.io.*; +import java.util.concurrent.*; +import javax.net.ssl.*; +import java.nio.file.*; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; +import jdk.testlibrary.SimpleSSLContext; +import static java.net.http.HttpRequest.*; +import static java.net.http.HttpResponse.*; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class EchoHandler implements HttpHandler { + public EchoHandler() {} + + @Override + public void handle(HttpExchange t) + throws IOException { + try { + System.err.println("EchoHandler received request to " + t.getRequestURI()); + InputStream is = t.getRequestBody(); + Headers map = t.getRequestHeaders(); + Headers map1 = t.getResponseHeaders(); + map1.add("X-Hello", "world"); + map1.add("X-Bye", "universe"); + String fixedrequest = map.getFirst("XFixed"); + File outfile = File.createTempFile("foo", "bar"); + FileOutputStream fos = new FileOutputStream(outfile); + int count = (int) is.transferTo(fos); + is.close(); + fos.close(); + InputStream is1 = new FileInputStream(outfile); + OutputStream os = null; + // return the number of bytes received (no echo) + String summary = map.getFirst("XSummary"); + if (fixedrequest != null && summary == null) { + t.sendResponseHeaders(200, count); + os = t.getResponseBody(); + is1.transferTo(os); + } else { + t.sendResponseHeaders(200, 0); + os = t.getResponseBody(); + is1.transferTo(os); + + if (summary != null) { + String s = Integer.toString(count); + os.write(s.getBytes()); + } + } + outfile.delete(); + os.close(); + is1.close(); + } catch (Throwable e) { + e.printStackTrace(); + throw new IOException(e); + } + } +} diff --git a/jdk/test/java/net/httpclient/LightWeightHttpServer.java b/jdk/test/java/net/httpclient/LightWeightHttpServer.java index 315849521a0..a0d6e9ac9c7 100644 --- a/jdk/test/java/net/httpclient/LightWeightHttpServer.java +++ b/jdk/test/java/net/httpclient/LightWeightHttpServer.java @@ -22,10 +22,10 @@ */ /** - * @library /lib/testlibrary/ - * @build jdk.testlibrary.SimpleSSLContext ProxyServer - * @compile ../../../com/sun/net/httpserver/LogFilter.java - * @compile ../../../com/sun/net/httpserver/FileServerHandler.java + * library /lib/testlibrary/ / + * build jdk.testlibrary.SimpleSSLContext ProxyServer EchoHandler + * compile ../../../com/sun/net/httpserver/LogFilter.java + * compile ../../../com/sun/net/httpserver/FileServerHandler.java */ import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpContext; diff --git a/jdk/test/java/net/httpclient/ManyRequests.java b/jdk/test/java/net/httpclient/ManyRequests.java index 10081f5def7..95b3ae38e6d 100644 --- a/jdk/test/java/net/httpclient/ManyRequests.java +++ b/jdk/test/java/net/httpclient/ManyRequests.java @@ -24,18 +24,17 @@ /** * @test * @bug 8087112 - * @library /lib/testlibrary/ - * @build jdk.testlibrary.SimpleSSLContext + * @library /lib/testlibrary/ / + * @build jdk.testlibrary.SimpleSSLContext EchoHandler * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java - * @run main/othervm ManyRequests + * @run main/othervm/timeout=40 -Djava.net.http.HttpClient.log=ssl ManyRequests * @summary Send a large number of requests asynchronously */ //package javaapplication16; -import com.sun.net.httpserver.HttpsConfigurator; -import com.sun.net.httpserver.HttpsServer; +import com.sun.net.httpserver.*; import java.io.IOException; import java.io.UncheckedIOException; import java.net.http.HttpClient; @@ -47,18 +46,25 @@ import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.Random; +import java.util.logging.*; import java.util.concurrent.CompletableFuture; -import javax.net.ssl.SSLContext; +import javax.net.ssl.*; import jdk.testlibrary.SimpleSSLContext; public class ManyRequests { + volatile static int counter = 0; + public static void main(String[] args) throws Exception { + Logger logger = Logger.getLogger("com.sun.net.httpserver"); + logger.setLevel(Level.ALL); + logger.info("TEST"); + SSLContext ctx = new SimpleSSLContext().get(); InetSocketAddress addr = new InetSocketAddress(0); HttpsServer server = HttpsServer.create(addr, 0); - server.setHttpsConfigurator(new HttpsConfigurator(ctx)); + server.setHttpsConfigurator(new Configurator(ctx)); HttpClient client = HttpClient.create() .sslContext(ctx) @@ -72,7 +78,8 @@ public class ManyRequests { } } - static final int REQUESTS = 1000; + //static final int REQUESTS = 1000; + static final int REQUESTS = 20; static void test(HttpsServer server, HttpClient client) throws Exception { int port = server.getAddress().getPort(); @@ -102,6 +109,9 @@ public class ManyRequests { resp.bodyAsync(HttpResponse.ignoreBody()); String s = "Expected 200, got: " + resp.statusCode(); return completedWithIOException(s); + } else { + counter++; + System.out.println("Result from " + counter); } return resp.bodyAsync(HttpResponse.asByteArray()) .thenApply((b) -> new Pair<>(resp, b)); @@ -114,14 +124,18 @@ public class ManyRequests { }); } + // wait for them all to complete and throw exception in case of error - CompletableFuture.allOf(results).join(); + //try { + CompletableFuture.allOf(results).join(); + //} catch (Exception e) { + //e.printStackTrace(); + //throw e; + //} } static CompletableFuture completedWithIOException(String message) { - CompletableFuture cf = new CompletableFuture<>(); - cf.completeExceptionally(new IOException(message)); - return cf; + return CompletableFuture.failedFuture(new IOException(message)); } static final class Pair { @@ -192,3 +206,14 @@ public class ManyRequests { throw new RuntimeException(sb.toString()); } } + +class Configurator extends HttpsConfigurator { + public Configurator(SSLContext ctx) { + super(ctx); + } + + public void configure (HttpsParameters params) { + params.setSSLParameters (getSSLContext().getSupportedSSLParameters()); + } +} + diff --git a/jdk/test/java/net/httpclient/RequestBodyTest.java b/jdk/test/java/net/httpclient/RequestBodyTest.java index 579f75edfb1..86478f9e5e1 100644 --- a/jdk/test/java/net/httpclient/RequestBodyTest.java +++ b/jdk/test/java/net/httpclient/RequestBodyTest.java @@ -23,10 +23,11 @@ /** * @test @bug 8087112 - * @library /lib/testlibrary/ - * @build jdk.testlibrary.SimpleSSLContext ProxyServer + * @library /lib/testlibrary/ / * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java + * @build LightWeightHttpServer + * @build jdk.testlibrary.SimpleSSLContext ProxyServer * @run main/othervm RequestBodyTest */ diff --git a/jdk/test/java/net/httpclient/SmokeTest.java b/jdk/test/java/net/httpclient/SmokeTest.java index ec516623179..5d8fde15c85 100644 --- a/jdk/test/java/net/httpclient/SmokeTest.java +++ b/jdk/test/java/net/httpclient/SmokeTest.java @@ -24,15 +24,13 @@ /** * @test * @bug 8087112 - * @library /lib/testlibrary/ - * @build jdk.testlibrary.SimpleSSLContext ProxyServer + * @library /lib/testlibrary/ / + * @build jdk.testlibrary.SimpleSSLContext ProxyServer EchoHandler * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java * @run main/othervm SmokeTest */ -//package javaapplication16; - import com.sun.net.httpserver.*; import java.net.*; import java.net.http.*; @@ -69,6 +67,7 @@ import java.util.logging.Logger; */ public class SmokeTest { static SSLContext ctx; + static SSLParameters sslparams; static HttpServer s1 ; static HttpsServer s2; static ExecutorService executor; @@ -107,6 +106,7 @@ public class SmokeTest { client = HttpClient.create() .sslContext(ctx) + .sslParameters(sslparams) .followRedirects(HttpClient.Redirect.ALWAYS) .executorService(Executors.newCachedThreadPool()) .build(); @@ -285,6 +285,7 @@ public class SmokeTest { HttpClient cl = HttpClient.create() .proxy(ProxySelector.of(proxyAddr)) .sslContext(ctx) + .sslParameters(sslparams) .build(); CompletableFuture fut = cl.request(uri) @@ -672,7 +673,8 @@ public class SmokeTest { s1.setExecutor(executor); s2.setExecutor(executor); ctx = new SimpleSSLContext().get(); - s2.setHttpsConfigurator(new HttpsConfigurator(ctx)); + sslparams = ctx.getSupportedSSLParameters(); + s2.setHttpsConfigurator(new Configurator(ctx)); s1.start(); s2.start(); @@ -689,6 +691,16 @@ public class SmokeTest { } } +class Configurator extends HttpsConfigurator { + public Configurator(SSLContext ctx) { + super(ctx); + } + + public void configure (HttpsParameters params) { + params.setSSLParameters (getSSLContext().getSupportedSSLParameters()); + } +} + class UploadServer extends Thread { int statusCode; ServerSocket ss; diff --git a/jdk/test/java/net/httpclient/TestKit.java b/jdk/test/java/net/httpclient/TestKit.java new file mode 100644 index 00000000000..308c004e16a --- /dev/null +++ b/jdk/test/java/net/httpclient/TestKit.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.regex.Pattern; + +import static java.util.Objects.requireNonNull; + +// +// A set of testing utility functions +// +public final class TestKit { + + private TestKit() { } + + public static void assertNotThrows(ThrowingProcedure code) { + requireNonNull(code, "code"); + assertNotThrows(() -> { + code.run(); + return null; + }); + } + + public static V assertNotThrows(ThrowingFunction code) { + requireNonNull(code, "code"); + try { + return code.run(); + } catch (Throwable t) { + throw new RuntimeException("Expected to run normally, but threw " + + t.getClass().getCanonicalName(), t); + } + } + + public static T assertThrows(Class clazz, + ThrowingProcedure code) { + requireNonNull(clazz, "clazz"); + requireNonNull(code, "code"); + try { + code.run(); + } catch (Throwable t) { + if (clazz.isInstance(t)) { + return clazz.cast(t); + } + throw new RuntimeException("Expected to catch an exception of type " + + clazz.getCanonicalName() + ", but caught " + + t.getClass().getCanonicalName(), t); + + } + throw new RuntimeException("Expected to catch an exception of type " + + clazz.getCanonicalName() + ", but caught nothing"); + } + + public interface ThrowingProcedure { + void run() throws Throwable; + } + + public interface ThrowingFunction { + V run() throws Throwable; + } + + // The rationale behind asking for a regex is to not pollute variable names + // space in the scope of assertion: if it's something as simple as checking + // a message, we can do it inside + public static T assertThrows(Class clazz, + String messageRegex, + ThrowingProcedure code) { + requireNonNull(messageRegex, "messagePattern"); + T t = assertThrows(clazz, code); + String m = t.getMessage(); + if (m == null) { + throw new RuntimeException(String.format( + "Expected exception message to match the regex '%s', " + + "but the message was null", messageRegex), t); + } + if (!Pattern.matches(messageRegex, m)) { + throw new RuntimeException(String.format( + "Expected exception message to match the regex '%s', " + + "actual message: %s", messageRegex, m), t); + } + return t; + } +} diff --git a/jdk/test/java/net/httpclient/TestKitTest.java b/jdk/test/java/net/httpclient/TestKitTest.java new file mode 100644 index 00000000000..da0f043191d --- /dev/null +++ b/jdk/test/java/net/httpclient/TestKitTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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.IOException; +import java.util.IllegalFormatException; +import java.util.Set; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +/* + * @test + * @compile TestKit.java + * @run testng TestKitTest + */ +public final class TestKitTest { + + public static void main(String[] args) { + testAssertNotThrows(); + testAssertThrows(); + } + + private static void testAssertNotThrows() { + Integer integer = TestKit.assertNotThrows( + () -> TestKit.assertNotThrows(() -> 1) + ); + assertEquals(integer, Integer.valueOf(1)); + + RuntimeException re = TestKit.assertThrows( + RuntimeException.class, + () -> TestKit.assertNotThrows(() -> { throw new IOException(); }) + ); + assertEquals(re.getMessage(), + "Expected to run normally, but threw " + + "java.io.IOException"); + + TestKit.assertNotThrows( + () -> TestKit.assertNotThrows(() -> { }) + ); + + re = TestKit.assertThrows( + RuntimeException.class, + () -> TestKit.assertNotThrows((TestKit.ThrowingProcedure) () -> { throw new IOException(); }) + ); + assertEquals(re.getMessage(), + "Expected to run normally, but threw " + + "java.io.IOException"); + } + + private static void testAssertThrows() { + NullPointerException npe = TestKit.assertThrows( + NullPointerException.class, + () -> TestKit.assertThrows(null, null) + ); + assertNotNull(npe); + assertTrue(Set.of("clazz", "code").contains(npe.getMessage()), npe.getMessage()); + + npe = TestKit.assertThrows( + NullPointerException.class, + () -> TestKit.assertThrows(IOException.class, null) + ); + assertNotNull(npe); + assertEquals(npe.getMessage(), "code"); + + npe = TestKit.assertThrows( + NullPointerException.class, + () -> TestKit.assertThrows(null, () -> { }) + ); + assertEquals(npe.getMessage(), "clazz"); + + npe = TestKit.assertThrows( + NullPointerException.class, + () -> { throw new NullPointerException(); } + ); + assertNotNull(npe); + assertNull(npe.getMessage()); + assertEquals(npe.getClass(), NullPointerException.class); + + RuntimeException re = TestKit.assertThrows( + RuntimeException.class, + () -> TestKit.assertThrows(NullPointerException.class, () -> { }) + ); + assertEquals(re.getClass(), RuntimeException.class); + assertEquals(re.getMessage(), + "Expected to catch an exception of type " + + "java.lang.NullPointerException, but caught nothing"); + + re = TestKit.assertThrows( + RuntimeException.class, + () -> { throw new NullPointerException(); } + ); + assertNotNull(re); + assertNull(re.getMessage()); + assertEquals(re.getClass(), NullPointerException.class); + + re = TestKit.assertThrows( + RuntimeException.class, + () -> TestKit.assertThrows( + IllegalFormatException.class, + () -> { throw new IndexOutOfBoundsException(); } + )); + assertNotNull(re); + assertEquals(re.getClass(), RuntimeException.class); + assertEquals(re.getMessage(), + "Expected to catch an exception of type java.util.IllegalFormatException" + + ", but caught java.lang.IndexOutOfBoundsException"); + } +} diff --git a/jdk/test/java/net/httpclient/http2/BasicTest.java b/jdk/test/java/net/httpclient/http2/BasicTest.java new file mode 100644 index 00000000000..0d53bbf1b04 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/BasicTest.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8087112 + * @library /lib/testlibrary + * @build jdk.testlibrary.SimpleSSLContext + * @modules java.httpclient + * @compile/module=java.httpclient java/net/http/BodyOutputStream.java + * @compile/module=java.httpclient java/net/http/BodyInputStream.java + * @compile/module=java.httpclient java/net/http/EchoHandler.java + * @compile/module=java.httpclient java/net/http/Http2Handler.java + * @compile/module=java.httpclient java/net/http/Http2TestExchange.java + * @compile/module=java.httpclient java/net/http/Http2TestServerConnection.java + * @compile/module=java.httpclient java/net/http/Http2TestServer.java + * @compile/module=java.httpclient java/net/http/OutgoingPushPromise.java + * @compile/module=java.httpclient java/net/http/TestUtil.java + * @run testng/othervm -Djava.net.http.HttpClient.log=ssl,requests,responses,errors BasicTest + */ + +import java.io.*; +import java.net.*; +import java.net.http.*; +import static java.net.http.HttpClient.Version.HTTP_2; +import javax.net.ssl.*; +import java.nio.file.*; +import java.util.concurrent.*; +import jdk.testlibrary.SimpleSSLContext; + + +import org.testng.annotations.Test; +import org.testng.annotations.Parameters; + +@Test +public class BasicTest { + static int httpPort, httpsPort; + static Http2TestServer httpServer, httpsServer; + static HttpClient client = null; + static ExecutorService exec; + static SSLContext sslContext; + + static String httpURIString, httpsURIString; + + static void initialize() throws Exception { + try { + SimpleSSLContext sslct = new SimpleSSLContext(); + sslContext = sslct.get(); + client = getClient(); + exec = client.executorService(); + httpServer = new Http2TestServer(false, 0, new EchoHandler(), + exec, sslContext); + httpPort = httpServer.getAddress().getPort(); + + httpsServer = new Http2TestServer(true, 0, new EchoHandler(), + exec, sslContext); + + httpsPort = httpsServer.getAddress().getPort(); + httpURIString = "http://127.0.0.1:" + Integer.toString(httpPort) + + "/foo/"; + httpsURIString = "https://127.0.0.1:" + Integer.toString(httpsPort) + + "/bar/"; + + httpServer.start(); + httpsServer.start(); + } catch (Throwable e) { + System.err.println("Throwing now"); + e.printStackTrace(); + throw e; + } + } + + @Test(timeOut=30000) + public static void test() throws Exception { + try { + initialize(); + simpleTest(false); + simpleTest(true); + streamTest(false); + streamTest(true); + Thread.sleep(1000 * 4); + } finally { + httpServer.stop(); + httpsServer.stop(); + exec.shutdownNow(); + } + } + + static HttpClient getClient() { + if (client == null) { + client = HttpClient.create() + .sslContext(sslContext) + .version(HTTP_2) + .build(); + } + return client; + } + + static URI getURI(boolean secure) { + if (secure) + return URI.create(httpsURIString); + else + return URI.create(httpURIString); + } + + static void checkStatus(int expected, int found) throws Exception { + if (expected != found) { + System.err.printf ("Test failed: wrong status code %d/%d\n", + expected, found); + throw new RuntimeException("Test failed"); + } + } + + static void checkStrings(String expected, String found) throws Exception { + if (!expected.equals(found)) { + System.err.printf ("Test failed: wrong string %s/%s\n", + expected, found); + throw new RuntimeException("Test failed"); + } + } + + static Void compareFiles(Path path1, Path path2) { + return java.net.http.TestUtil.compareFiles(path1, path2); + } + + static Path tempFile() { + return java.net.http.TestUtil.tempFile(); + } + + static final String SIMPLE_STRING = "Hello world Goodbye world"; + + static final int LOOPS = 13; + static final int FILESIZE = 64 * 1024; + + static void streamTest(boolean secure) throws Exception { + URI uri = getURI(secure); + System.err.printf("streamTest %b to %s\n" , secure, uri); + + HttpClient client = getClient(); + Path src = java.net.http.TestUtil.getAFile(FILESIZE * 4); + HttpRequest req = client.request(uri) + .body(HttpRequest.fromFile(src)) + .POST(); + + CompletableFuture response = req.responseAsync() + .thenCompose(resp -> { + if (resp.statusCode() != 200) + throw new RuntimeException(); + return resp.bodyAsync(HttpResponse.asInputStream()); + }); + InputStream is = response.join(); + File dest = File.createTempFile("foo","bar"); + dest.deleteOnExit(); + FileOutputStream os = new FileOutputStream(dest); + is.transferTo(os); + is.close(); + os.close(); + int count = 0; + compareFiles(src, dest.toPath()); + System.err.println("DONE"); + } + + + static void simpleTest(boolean secure) throws Exception { + URI uri = getURI(secure); + System.err.println("Request to " + uri); + + // Do a simple warmup request + + HttpClient client = getClient(); + HttpRequest req = client.request(uri) + .body(HttpRequest.fromString(SIMPLE_STRING)) + .POST(); + HttpResponse response = req.response(); + HttpHeaders h = response.headers(); + + checkStatus(200, response.statusCode()); + + String responseBody = response.body(HttpResponse.asString()); + checkStrings(SIMPLE_STRING, responseBody); + + checkStrings(h.firstValue("x-hello").get(), "world"); + checkStrings(h.firstValue("x-bye").get(), "universe"); + + // Do loops asynchronously + + CompletableFuture[] responses = new CompletableFuture[LOOPS]; + final Path source = java.net.http.TestUtil.getAFile(FILESIZE); + for (int i = 0; i < LOOPS; i++) { + responses[i] = client.request(uri) + .body(HttpRequest.fromFile(source)) + .version(HTTP_2) + .POST() + .responseAsync() + .thenCompose(r -> r.bodyAsync(HttpResponse.asFile(tempFile()))) + .thenApply(path -> compareFiles(path, source)); + Thread.sleep(100); + } + CompletableFuture.allOf(responses).join(); + System.err.println("DONE"); + } +} diff --git a/jdk/test/java/net/httpclient/http2/ServerPush.java b/jdk/test/java/net/httpclient/http2/ServerPush.java new file mode 100644 index 00000000000..57a72ec9f06 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/ServerPush.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8087112 + * @library /lib/testlibrary + * @build jdk.testlibrary.SimpleSSLContext + * @modules java.httpclient + * @compile/module=java.httpclient java/net/http/BodyOutputStream.java + * @compile/module=java.httpclient java/net/http/BodyInputStream.java + * @compile/module=java.httpclient java/net/http/PushHandler.java + * @compile/module=java.httpclient java/net/http/Http2Handler.java + * @compile/module=java.httpclient java/net/http/Http2TestExchange.java + * @compile/module=java.httpclient java/net/http/Http2TestServerConnection.java + * @compile/module=java.httpclient java/net/http/Http2TestServer.java + * @compile/module=java.httpclient java/net/http/OutgoingPushPromise.java + * @compile/module=java.httpclient java/net/http/TestUtil.java + * @run testng/othervm -Djava.net.http.HttpClient.log=requests,responses ServerPush + */ + +import java.io.*; +import java.net.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.net.http.*; +import java.util.*; +import java.util.concurrent.*; +import org.testng.annotations.Test; + +public class ServerPush { + + static ExecutorService e = Executors.newCachedThreadPool(); + + static final int LOOPS = 13; + static final int FILE_SIZE = 32 * 1024; + + static Path tempFile; + + @Test(timeOut=30000) + public static void test() throws Exception { + Http2TestServer server = null; + Path dir = null; + try { + server = new Http2TestServer(false, 0, + new PushHandler(FILE_SIZE, LOOPS)); + tempFile = TestUtil.getAFile(FILE_SIZE); + + System.err.println("Server listening on port " + server.getAddress().getPort()); + server.start(); + int port = server.getAddress().getPort(); + dir = Files.createTempDirectory("serverPush"); + + URI uri = new URI("http://127.0.0.1:" + Integer.toString(port) + "/foo"); + HttpRequest request = HttpRequest.create(uri) + .version(HttpClient.Version.HTTP_2) + .GET(); + + CompletableFuture> cf = + request.multiResponseAsync(HttpResponse.multiFile(dir)); + Map results = cf.get(); + + //HttpResponse resp = request.response(); + System.err.println(results.size()); + Set uris = results.keySet(); + for (URI u : uris) { + Path result = results.get(u); + System.err.printf("%s -> %s\n", u.toString(), result.toString()); + TestUtil.compareFiles(result, tempFile); + } + System.out.println("TEST OK"); + } finally { + e.shutdownNow(); + server.stop(); + Files.walkFileTree(dir, new SimpleFileVisitor() { + public FileVisitResult postVisitDirectory(Path dir, IOException exc) { + dir.toFile().delete(); + return FileVisitResult.CONTINUE; + } + public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { + path.toFile().delete(); + return FileVisitResult.CONTINUE; + } + }); + } + } +} diff --git a/jdk/test/java/net/httpclient/http2/TEST.properties b/jdk/test/java/net/httpclient/http2/TEST.properties new file mode 100644 index 00000000000..8abaaefc34c --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/TEST.properties @@ -0,0 +1 @@ +bootclasspath.dirs = /java/net/httpclient diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyInputStream.java b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyInputStream.java new file mode 100644 index 00000000000..405003ed143 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyInputStream.java @@ -0,0 +1,107 @@ +package java.net.http; + +import java.io.*; +import java.nio.ByteBuffer; + +/** + * InputStream reads frames off stream q and supplies read demand from any + * DataFrames it finds. Window updates are sent back on the connections send + * q. + */ +class BodyInputStream extends InputStream { + + final Queue q; + final int streamid; + boolean closed; + boolean eof; + final Http2TestServerConnection conn; + + @SuppressWarnings({"rawtypes","unchecked"}) + BodyInputStream(Queue q, int streamid, Http2TestServerConnection conn) { + this.q = q; + this.streamid = streamid; + this.conn = conn; + } + + DataFrame df; + ByteBuffer[] buffers; + ByteBuffer buffer; + int nextIndex = -1; + + private DataFrame getData() throws IOException { + if (eof) { + return null; + } + Http2Frame frame; + do { + frame = q.take(); + if (frame.type() == ResetFrame.TYPE) { + conn.handleStreamReset((ResetFrame) frame); // throws IOException + } + // ignoring others for now Wupdates handled elsewhere + if (frame.type() != DataFrame.TYPE) { + System.out.println("Ignoring " + frame.toString() + " CHECK THIS"); + } + } while (frame.type() != DataFrame.TYPE); + df = (DataFrame) frame; + int len = df.getDataLength(); + eof = frame.getFlag(DataFrame.END_STREAM); + // acknowledge + conn.sendWindowUpdates(len, streamid); + return (DataFrame) frame; + } + + // null return means EOF + private ByteBuffer getBuffer() throws IOException { + if (buffer == null || !buffer.hasRemaining()) { + if (nextIndex == -1 || nextIndex == buffers.length) { + DataFrame df = getData(); + if (df == null) { + return null; + } + int len = df.getDataLength(); + if ((len == 0) && eof) { + return null; + } + buffers = df.getData(); + nextIndex = 0; + } + buffer = buffers[nextIndex++]; + } + return buffer; + } + + @Override + public int read(byte[] buf, int offset, int length) throws IOException { + if (closed) { + throw new IOException("closed"); + } + ByteBuffer b = getBuffer(); + if (b == null) { + return -1; + } + int remaining = b.remaining(); + if (remaining < length) { + length = remaining; + } + b.get(buf, offset, length); + return length; + } + + byte[] one = new byte[1]; + + @Override + public int read() throws IOException { + int c = read(one, 0, 1); + if (c == -1) { + return -1; + } + return one[0]; + } + + @Override + public void close() { + // TODO reset this stream + closed = true; + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyOutputStream.java b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyOutputStream.java new file mode 100644 index 00000000000..ed77cfc17ce --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyOutputStream.java @@ -0,0 +1,106 @@ +package java.net.http; + +import java.io.*; +import java.nio.ByteBuffer; + +/** + * OutputStream. Incoming window updates handled by the main connection + * reader thread. + */ +@SuppressWarnings({"rawtypes","unchecked"}) +class BodyOutputStream extends OutputStream { + final static byte[] EMPTY_BARRAY = new byte[0]; + + final int streamid; + int window; + boolean closed; + boolean goodToGo = false; // not allowed to send until headers sent + final Http2TestServerConnection conn; + final Queue outputQ; + + BodyOutputStream(int streamid, int initialWindow, Http2TestServerConnection conn) { + this.window = initialWindow; + this.streamid = streamid; + this.conn = conn; + this.outputQ = conn.outputQ; + conn.registerStreamWindowUpdater(streamid, this::updateWindow); + } + + // called from connection reader thread as all incoming window + // updates are handled there. + synchronized void updateWindow(int update) { + window += update; + notifyAll(); + } + + void waitForWindow(int demand) throws InterruptedException { + // first wait for the connection window + conn.obtainConnectionWindow(demand); + // now wait for the stream window + synchronized (this) { + while (demand > 0) { + int n = Math.min(demand, window); + demand -= n; + window -= n; + if (demand > 0) { + wait(); + } + } + } + } + + void goodToGo() { + goodToGo = true; + } + + @Override + public void write(byte[] buf, int offset, int len) throws IOException { + if (closed) { + throw new IOException("closed"); + } + + if (!goodToGo) { + throw new IllegalStateException("sendResponseHeaders must be called first"); + } + try { + waitForWindow(len); + send(buf, offset, len, 0); + } catch (InterruptedException ex) { + throw new IOException(ex); + } + } + + private void send(byte[] buf, int offset, int len, int flags) throws IOException { + ByteBuffer buffer = ByteBuffer.allocate(len); + buffer.put(buf, offset, len); + buffer.flip(); + DataFrame df = new DataFrame(); + assert streamid != 0; + df.streamid(streamid); + df.setFlags(flags); + df.setData(buffer); + outputQ.put(df); + } + + byte[] one = new byte[1]; + + @Override + public void write(int b) throws IOException { + one[0] = (byte) b; + write(one, 0, 1); + } + + @Override + public void close() { + if (closed) { + return; + } + closed = true; + try { + send(EMPTY_BARRAY, 0, 0, DataFrame.END_STREAM); + } catch (IOException ex) { + System.err.println("TestServer: OutputStream.close exception: " + ex); + ex.printStackTrace(); + } + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/EchoHandler.java b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/EchoHandler.java new file mode 100644 index 00000000000..a568ff84029 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/EchoHandler.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.net.http; + +import java.util.*; +import java.util.concurrent.*; +import java.io.*; +import java.net.*; + +public class EchoHandler implements Http2Handler { + public EchoHandler() {} + + @Override + public void handle(Http2TestExchange t) + throws IOException { + try { + System.err.println("EchoHandler received request to " + t.getRequestURI()); + InputStream is = t.getRequestBody(); + HttpHeadersImpl map = t.getRequestHeaders(); + HttpHeadersImpl map1 = t.getResponseHeaders(); + map1.addHeader("X-Hello", "world"); + map1.addHeader("X-Bye", "universe"); + String fixedrequest = map.firstValue("XFixed").orElse(null); + File outfile = File.createTempFile("foo", "bar"); + FileOutputStream fos = new FileOutputStream(outfile); + int count = (int) is.transferTo(fos); + System.err.printf("EchoHandler read %d bytes\n", count); + is.close(); + fos.close(); + InputStream is1 = new FileInputStream(outfile); + OutputStream os = null; + // return the number of bytes received (no echo) + String summary = map.firstValue("XSummary").orElse(null); + if (fixedrequest != null && summary == null) { + t.sendResponseHeaders(200, count); + os = t.getResponseBody(); + is1.transferTo(os); + } else { + t.sendResponseHeaders(200, 0); + os = t.getResponseBody(); + int count1 = (int)is1.transferTo(os); + System.err.printf("EchoHandler wrote %d bytes\n", count1); + + if (summary != null) { + String s = Integer.toString(count); + os.write(s.getBytes()); + } + } + outfile.delete(); + os.close(); + is1.close(); + } catch (Throwable e) { + e.printStackTrace(); + throw new IOException(e); + } + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2Handler.java b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2Handler.java new file mode 100644 index 00000000000..8ac77c4a770 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2Handler.java @@ -0,0 +1,18 @@ +package java.net.http; + +import java.io.IOException; + +/** + * A handler which is invoked to process HTTP exchanges. Each + * HTTP exchange is handled by one of these handlers. + */ +public interface Http2Handler { + /** + * Handle the given request and generate an appropriate response. + * @param exchange the exchange containing the request from the + * client and used to send the response + * @throws NullPointerException if exchange is null + */ + public abstract void handle (Http2TestExchange exchange) throws IOException; +} + diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestExchange.java b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestExchange.java new file mode 100644 index 00000000000..4b9ce043001 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestExchange.java @@ -0,0 +1,126 @@ +package java.net.http; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.InetSocketAddress; + +public class Http2TestExchange { + + final HttpHeadersImpl reqheaders; + final HttpHeadersImpl rspheaders; + final URI uri; + final String method; + final InputStream is; + final BodyOutputStream os; + final int streamid; + final boolean pushAllowed; + final Http2TestServerConnection conn; + final Http2TestServer server; + + int responseCode = -1; + long responseLength; + + Http2TestExchange(int streamid, String method, HttpHeadersImpl reqheaders, + HttpHeadersImpl rspheaders, URI uri, InputStream is, + BodyOutputStream os, Http2TestServerConnection conn, boolean pushAllowed) { + this.reqheaders = reqheaders; + this.rspheaders = rspheaders; + this.uri = uri; + this.method = method; + this.is = is; + this.streamid = streamid; + this.os = os; + this.pushAllowed = pushAllowed; + this.conn = conn; + this.server = conn.server; + } + + public HttpHeadersImpl getRequestHeaders() { + return reqheaders; + } + + public HttpHeadersImpl getResponseHeaders() { + return rspheaders; + } + + public URI getRequestURI() { + return uri; + } + + public String getRequestMethod() { + return method; + } + + public void close() { + try { + is.close(); + os.close(); + } catch (IOException e) { + System.err.println("TestServer: HttpExchange.close exception: " + e); + e.printStackTrace(); + } + } + + public InputStream getRequestBody() { + return is; + } + + public OutputStream getResponseBody() { + return os; + } + + public void sendResponseHeaders(int rCode, long responseLength) throws IOException { + this.responseLength = responseLength; + if (responseLength > 0 || responseLength < 0) { + long clen = responseLength > 0 ? responseLength : 0; + rspheaders.setHeader("Content-length", Long.toString(clen)); + } + + rspheaders.setHeader(":status", Integer.toString(rCode)); + + Http2TestServerConnection.ResponseHeaders response + = new Http2TestServerConnection.ResponseHeaders(rspheaders); + response.streamid(streamid); + response.setFlag(HeaderFrame.END_HEADERS); + conn.outputQ.put(response); + os.goodToGo(); + System.err.println("Sent response headers " + rCode); + } + + public InetSocketAddress getRemoteAddress() { + return (InetSocketAddress) conn.socket.getRemoteSocketAddress(); + } + + public int getResponseCode() { + return responseCode; + } + + public InetSocketAddress getLocalAddress() { + return server.getAddress(); + } + + public String getProtocol() { + return "HTTP/2"; + } + + public boolean serverPushAllowed() { + return pushAllowed; + } + + public void serverPush(URI uri, HttpHeadersImpl headers, InputStream content) { + OutgoingPushPromise pp = new OutgoingPushPromise( + streamid, uri, headers, content); + headers.setHeader(":method", "GET"); + headers.setHeader(":scheme", uri.getScheme()); + headers.setHeader(":authority", uri.getAuthority()); + headers.setHeader(":path", uri.getPath()); + try { + conn.outputQ.put(pp); + // writeLoop will spin up thread to read the InputStream + } catch (IOException ex) { + System.err.println("TestServer: pushPromise exception: " + ex); + } + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServer.java b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServer.java new file mode 100644 index 00000000000..667a1d6ec55 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServer.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.net.http; + +import java.io.IOException; +import java.net.*; +import java.util.HashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import javax.net.ServerSocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + +/** + * Waits for incoming TCP connections from a client and establishes + * a HTTP2 connection. Two threads are created per connection. One for reading + * and one for writing. Incoming requests are dispatched to the supplied + * Http2Handler on additional threads. All threads + * obtained from the supplied ExecutorService. + */ +public class Http2TestServer { + final ServerSocket server; + boolean secure; + SettingsFrame serverSettings, clientSettings; + final ExecutorService exec; + volatile boolean stopping = false; + final Http2Handler handler; + final SSLContext sslContext; + final HashMap connections; + + private static ThreadFactory defaultThreadFac = + (Runnable r) -> { + Thread t = new Thread(r); + t.setName("Test-server-pool"); + return t; + }; + + + private static ExecutorService getDefaultExecutor() { + return Executors.newCachedThreadPool(defaultThreadFac); + } + + public Http2TestServer(boolean secure, int port, Http2Handler handler) throws Exception { + this(secure, port, handler, getDefaultExecutor(), null); + } + + public InetSocketAddress getAddress() { + return (InetSocketAddress)server.getLocalSocketAddress(); + } + + /** + * Create a Http2Server listening on the given port. Currently needs + * to know in advance whether incoming connections are plain TCP "h2c" + * or TLS "h2"/ + * + * @param secure https or http + * @param port listen port + * @param handler the handler which receives incoming requests + * @param exec executor service (cached thread pool is used if null) + * @param context the SSLContext used when secure is true + * @throws Exception + */ + public Http2TestServer(boolean secure, int port, Http2Handler handler, + ExecutorService exec, SSLContext context) throws Exception { + if (secure) { + server = initSecure(port); + } else { + server = initPlaintext(port); + } + this.secure = secure; + this.exec = exec == null ? getDefaultExecutor() : exec; + this.handler = handler; + this.sslContext = context; + this.connections = new HashMap<>(); + } + + final ServerSocket initPlaintext(int port) throws Exception { + return new ServerSocket(port); + } + + public void stop() { + // TODO: clean shutdown GoAway + stopping = true; + for (Http2TestServerConnection connection : connections.values()) { + connection.close(); + } + try { + server.close(); + } catch (IOException e) {} + exec.shutdownNow(); + } + + + final ServerSocket initSecure(int port) throws Exception { + ServerSocketFactory fac; + if (sslContext != null) { + fac = sslContext.getServerSocketFactory(); + } else { + fac = SSLServerSocketFactory.getDefault(); + } + SSLServerSocket se = (SSLServerSocket) fac.createServerSocket(port); + SSLParameters sslp = se.getSSLParameters(); + sslp.setApplicationProtocols(new String[]{"h2"}); + se.setSSLParameters(sslp); + se.setEnabledCipherSuites(se.getSupportedCipherSuites()); + se.setEnabledProtocols(se.getSupportedProtocols()); + // other initialisation here + return se; + } + + /** + * Start thread which waits for incoming connections. + * + * @throws Exception + */ + public void start() { + exec.submit(() -> { + try { + while (!stopping) { + Socket socket = server.accept(); + InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress(); + Http2TestServerConnection c = new Http2TestServerConnection(this, socket); + connections.put(addr, c); + c.run(); + } + } catch (Throwable e) { + if (!stopping) { + System.err.println("TestServer: start exception: " + e); + e.printStackTrace(); + } + } + }); + } + +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServerConnection.java b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServerConnection.java new file mode 100644 index 00000000000..2f56f8a3dfb --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServerConnection.java @@ -0,0 +1,730 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.net.http; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import static java.net.http.SettingsFrame.HEADER_TABLE_SIZE; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; +import sun.net.httpclient.hpack.Decoder; +import sun.net.httpclient.hpack.DecodingCallback; +import sun.net.httpclient.hpack.Encoder; + +/** + * Represents one HTTP2 connection, either plaintext upgraded from HTTP/1.1 + * or HTTPS opened using "h2" ALPN. + */ +public class Http2TestServerConnection { + final Http2TestServer server; + @SuppressWarnings({"rawtypes","unchecked"}) + final Map streams; // input q per stream + final Queue outputQ; + int nextstream; + final Socket socket; + final InputStream is; + final OutputStream os; + Encoder hpackOut; + Decoder hpackIn; + SettingsFrame clientSettings, serverSettings; + final ExecutorService exec; + final boolean secure; + final Http2Handler handler; + volatile boolean stopping; + int nextPushStreamId = 2; + + final static ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); + final static byte[] EMPTY_BARRAY = new byte[0]; + + final static byte[] clientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes(); + + Http2TestServerConnection(Http2TestServer server, Socket socket) throws IOException { + System.err.println("New connection from " + socket); + this.server = server; + this.streams = Collections.synchronizedMap(new HashMap<>()); + this.outputQ = new Queue<>(); + this.socket = socket; + this.clientSettings = server.clientSettings; + this.serverSettings = server.serverSettings; + this.exec = server.exec; + this.secure = server.secure; + this.handler = server.handler; + is = new BufferedInputStream(socket.getInputStream()); + os = new BufferedOutputStream(socket.getOutputStream()); + } + + void close() { + streams.forEach((i, q) -> { + q.close(); + }); + stopping = true; + try { + socket.close(); + // TODO: put a reset on each stream + } catch (IOException e) { + } + } + + private void readPreface() throws IOException { + int len = clientPreface.length; + byte[] bytes = new byte[len]; + is.readNBytes(bytes, 0, len); + if (Arrays.compare(clientPreface, bytes) != 0) { + throw new IOException("Invalid preface: " + new String(bytes, 0, len)); + } + } + + String doUpgrade() throws IOException { + String upgrade = readHttp1Request(); + String h2c = getHeader(upgrade, "Upgrade"); + if (h2c == null || !h2c.equals("h2c")) { + throw new IOException("Bad upgrade 1 " + h2c); + } + + sendHttp1Response(101, "Switching Protocols", "Connection", "Upgrade", + "Upgrade", "h2c"); + + sendSettingsFrame(); + readPreface(); + + String clientSettingsString = getHeader(upgrade, "HTTP2-Settings"); + clientSettings = getSettingsFromString(clientSettingsString); + + return upgrade; + } + + /** + * Client settings payload provided in base64 HTTP1 header. Decode it + * and add a header so we can interpret it. + * + * @param s + * @return + * @throws IOException + */ + private SettingsFrame getSettingsFromString(String s) throws IOException { + Base64.Decoder decoder = Base64.getUrlDecoder(); + byte[] payload = decoder.decode(s); + ByteBuffer bb1 = ByteBuffer.wrap(payload); + // simulate header of Settings Frame + ByteBuffer bb0 = ByteBuffer.wrap( + new byte[] {0, 0, (byte)payload.length, 4, 0, 0, 0, 0, 0}); + ByteBufferConsumer bbc = new ByteBufferConsumer( + new LinkedList(List.of(bb0, bb1)), + this::getBuffer); + Http2Frame frame = Http2Frame.readIncoming(bbc); + if (!(frame instanceof SettingsFrame)) + throw new IOException("Expected SettingsFrame"); + return (SettingsFrame)frame; + } + + void run() throws Exception { + String upgrade = null; + if (!secure) { + upgrade = doUpgrade(); + } else { + readPreface(); + sendSettingsFrame(true); + clientSettings = (SettingsFrame) readFrame(); + nextstream = 1; + } + + hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE)); + hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE)); + + exec.submit(() -> { + readLoop(); + }); + exec.submit(() -> { + writeLoop(); + }); + if (!secure) { + createPrimordialStream(upgrade); + nextstream = 3; + } + } + + static class BufferPool implements BufferHandler { + + public void setMinBufferSize(int size) { + } + + public ByteBuffer getBuffer(int size) { + if (size == -1) + size = 32 * 1024; + return ByteBuffer.allocate(size); + } + + public void returnBuffer(ByteBuffer buffer) { + } + } + + static BufferPool bufferpool = new BufferPool(); + + private void writeFrame(Http2Frame frame) throws IOException { + ByteBufferGenerator bg = new ByteBufferGenerator(bufferpool); + frame.computeLength(); + System.err.println("Writing frame " + frame.toString()); + frame.writeOutgoing(bg); + ByteBuffer[] bufs = bg.getBufferArray(); + int c = 0; + for (ByteBuffer buf : bufs) { + byte[] ba = buf.array(); + int start = buf.arrayOffset() + buf.position(); + c += buf.remaining(); + os.write(ba, start, buf.remaining()); + } + os.flush(); + System.err.printf("wrote %d bytes\n", c); + } + + void handleStreamReset(ResetFrame resetFrame) throws IOException { + // TODO: cleanup + throw new IOException("Stream reset"); + } + + private void handleCommonFrame(Http2Frame f) throws IOException { + if (f instanceof SettingsFrame) { + serverSettings = (SettingsFrame) f; + if (serverSettings.getFlag(SettingsFrame.ACK)) // ignore + { + return; + } + // otherwise acknowledge it + SettingsFrame frame = new SettingsFrame(); + frame.setFlag(SettingsFrame.ACK); + frame.streamid(0); + outputQ.put(frame); + return; + } + System.err.println("Received ---> " + f.toString()); + throw new UnsupportedOperationException("Not supported yet."); + } + + void sendWindowUpdates(int len, int streamid) throws IOException { + if (len == 0) + return; + WindowUpdateFrame wup = new WindowUpdateFrame(); + wup.streamid(streamid); + wup.setUpdate(len); + outputQ.put(wup); + wup = new WindowUpdateFrame(); + wup.streamid(0); + wup.setUpdate(len); + outputQ.put(wup); + } + + HttpHeadersImpl decodeHeaders(List frames) { + HttpHeadersImpl headers = new HttpHeadersImpl(); + + DecodingCallback cb = (name, value) -> { + headers.addHeader(name.toString(), value.toString()); + }; + + for (HeaderFrame frame : frames) { + ByteBuffer[] buffers = frame.getHeaderBlock(); + for (ByteBuffer buffer : buffers) { + hpackIn.decode(buffer, false, cb); + } + } + hpackIn.decode(EMPTY_BUFFER, true, cb); + return headers; + } + + String getRequestLine(String request) { + int eol = request.indexOf(CRLF); + return request.substring(0, eol); + } + + // First stream (1) comes from a plaintext HTTP/1.1 request + @SuppressWarnings({"rawtypes","unchecked"}) + void createPrimordialStream(String request) throws IOException { + HttpHeadersImpl headers = new HttpHeadersImpl(); + String requestLine = getRequestLine(request); + String[] tokens = requestLine.split(" "); + if (!tokens[2].equals("HTTP/1.1")) { + throw new IOException("bad request line"); + } + URI uri = null; + try { + uri = new URI(tokens[1]); + } catch (URISyntaxException e) { + throw new IOException(e); + } + String host = getHeader(request, "Host"); + if (host == null) { + throw new IOException("missing Host"); + } + + headers.setHeader(":method", tokens[0]); + headers.setHeader(":scheme", "http"); // always in this case + headers.setHeader(":authority", host); + headers.setHeader(":path", uri.getPath()); + Queue q = new Queue(); + String body = getRequestBody(request); + headers.setHeader("Content-length", Integer.toString(body.length())); + + addRequestBodyToQueue(body, q); + streams.put(1, q); + exec.submit(() -> { + handleRequest(headers, q, 1); + }); + } + + // all other streams created here + @SuppressWarnings({"rawtypes","unchecked"}) + void createStream(HeaderFrame frame) throws IOException { + List frames = new LinkedList<>(); + frames.add(frame); + int streamid = frame.streamid(); + if (streamid != nextstream) { + throw new IOException("unexpected stream id"); + } + nextstream += 2; + + while (!frame.getFlag(HeaderFrame.END_HEADERS)) { + Http2Frame f = readFrame(); + if (!(f instanceof HeaderFrame)) { + handleCommonFrame(f); // should only be error frames + } else { + frame = (HeaderFrame) f; + frames.add(frame); + } + } + HttpHeadersImpl headers = decodeHeaders(frames); + Queue q = new Queue(); + streams.put(streamid, q); + exec.submit(() -> { + handleRequest(headers, q, streamid); + }); + } + + // runs in own thread. Handles request from start to finish. Incoming frames + // for this stream/request delivered on Q + + @SuppressWarnings({"rawtypes","unchecked"}) + void handleRequest(HttpHeadersImpl headers, Queue queue, int streamid) { + String method = headers.firstValue(":method").orElse(""); + System.out.println("method = " + method); + String path = headers.firstValue(":path").orElse(""); + System.out.println("path = " + path); + String scheme = headers.firstValue(":scheme").orElse(""); + System.out.println("scheme = " + scheme); + String authority = headers.firstValue(":authority").orElse(""); + System.out.println("authority = " + authority); + HttpHeadersImpl rspheaders = new HttpHeadersImpl(); + int winsize = clientSettings.getParameter( + SettingsFrame.INITIAL_WINDOW_SIZE); + System.err.println ("Stream window size = " + winsize); + try ( + BodyInputStream bis = new BodyInputStream(queue, streamid, this); + BodyOutputStream bos = new BodyOutputStream(streamid, winsize, this); + ) + { + String us = scheme + "://" + authority + path; + URI uri = new URI(us); + boolean pushAllowed = clientSettings.getParameter(SettingsFrame.ENABLE_PUSH) == 1; + Http2TestExchange exchange = new Http2TestExchange(streamid, method, + headers, rspheaders, uri, bis, bos, this, pushAllowed); + + // give to user + handler.handle(exchange); + + // everything happens in the exchange from here. Hopefully will + // return though. + } catch (Throwable e) { + System.err.println("TestServer: handleRequest exception: " + e); + e.printStackTrace(); + } + } + + // Runs in own thread + + @SuppressWarnings({"rawtypes","unchecked"}) + void readLoop() { + try { + while (!stopping) { + Http2Frame frame = readFrame(); + int stream = frame.streamid(); + if (stream == 0) { + if (frame.type() == WindowUpdateFrame.TYPE) { + WindowUpdateFrame wup = (WindowUpdateFrame) frame; + updateConnectionWindow(wup.getUpdate()); + } else { + // other common frame types + handleCommonFrame(frame); + } + } else { + Queue q = streams.get(stream); + if (frame.type() == HeadersFrame.TYPE) { + if (q != null) { + System.err.println("HEADERS frame for existing stream! Error."); + // TODO: close connection + continue; + } else { + createStream((HeadersFrame) frame); + } + } else { + if (q == null) { + System.err.printf("Non Headers frame received with"+ + " non existing stream (%d) ", frame.streamid()); + System.err.println(frame); + continue; + } + if (frame.type() == WindowUpdateFrame.TYPE) { + WindowUpdateFrame wup = (WindowUpdateFrame) frame; + synchronized (updaters) { + Consumer r = updaters.get(stream); + r.accept(wup.getUpdate()); + } + } else { + q.put(frame); + } + } + } + } + } catch (Throwable e) { + close(); + if (!stopping) { + System.err.println("Http server reader thread shutdown"); + e.printStackTrace(); + } + } + } + + // set streamid outside plus other specific fields + void encodeHeaders(HttpHeadersImpl headers, HeaderFrame out) { + List buffers = new LinkedList<>(); + + ByteBuffer buf = getBuffer(); + boolean encoded; + for (Map.Entry> entry : headers.map().entrySet()) { + List values = entry.getValue(); + String key = entry.getKey().toLowerCase(); + for (String value : values) { + do { + hpackOut.header(key, value); + encoded = hpackOut.encode(buf); + if (!encoded) { + buf.flip(); + buffers.add(buf); + buf = getBuffer(); + } + } while (!encoded); + } + } + buf.flip(); + buffers.add(buf); + out.setFlags(HeaderFrame.END_HEADERS); + out.setHeaderBlock(buffers.toArray(bbarray)); + } + + static void closeIgnore(Closeable c) { + try { + c.close(); + } catch (IOException e) {} + } + + // Runs in own thread + void writeLoop() { + try { + while (!stopping) { + Http2Frame frame = outputQ.take(); + if (frame instanceof ResponseHeaders) { + ResponseHeaders rh = (ResponseHeaders)frame; + HeadersFrame hf = new HeadersFrame(); + encodeHeaders(rh.headers, hf); + hf.streamid(rh.streamid()); + writeFrame(hf); + } else if (frame instanceof OutgoingPushPromise) { + handlePush((OutgoingPushPromise)frame); + } else + writeFrame(frame); + } + System.err.println("Connection writer stopping"); + } catch (Throwable e) { + e.printStackTrace(); + /*close(); + if (!stopping) { + e.printStackTrace(); + System.err.println("TestServer: writeLoop exception: " + e); + }*/ + } + } + + private void handlePush(OutgoingPushPromise op) throws IOException { + PushPromiseFrame pp = new PushPromiseFrame(); + encodeHeaders(op.headers, pp); + int promisedStreamid = nextPushStreamId; + nextPushStreamId += 2; + pp.streamid(op.parentStream); + pp.setPromisedStream(promisedStreamid); + writeFrame(pp); + final InputStream ii = op.is; + final BodyOutputStream oo = new BodyOutputStream( + promisedStreamid, + clientSettings.getParameter( + SettingsFrame.INITIAL_WINDOW_SIZE), this); + oo.goodToGo(); + exec.submit(() -> { + try { + ResponseHeaders oh = getPushResponse(promisedStreamid); + outputQ.put(oh); + ii.transferTo(oo); + } catch (Throwable ex) { + System.err.printf("TestServer: pushing response error: %s\n", + ex.toString()); + } finally { + closeIgnore(ii); + closeIgnore(oo); + } + }); + + } + + // returns a minimal response with status 200 + // that is the response to the push promise just sent + private ResponseHeaders getPushResponse(int streamid) { + HttpHeadersImpl h = new HttpHeadersImpl(); + h.addHeader(":status", "200"); + ResponseHeaders oh = new ResponseHeaders(h); + oh.streamid(streamid); + return oh; + } + + private ByteBuffer getBuffer() { + return ByteBuffer.allocate(8 * 1024); + } + + private Http2Frame readFrame() throws IOException { + byte[] buf = new byte[9]; + if (is.readNBytes(buf, 0, 9) != 9) + throw new IOException("readFrame: connection closed"); + int len = 0; + for (int i = 0; i < 3; i++) { + int n = buf[i] & 0xff; + //System.err.println("n = " + n); + len = (len << 8) + n; + } + byte[] rest = new byte[len]; + int n = is.readNBytes(rest, 0, len); + if (n != len) + throw new IOException("Error reading frame"); + ByteBufferConsumer bc = new ByteBufferConsumer( + new LinkedList(List.of(ByteBuffer.wrap(buf), ByteBuffer.wrap(rest))), + this::getBuffer); + return Http2Frame.readIncoming(bc); + } + + void sendSettingsFrame() throws IOException { + sendSettingsFrame(false); + } + + void sendSettingsFrame(boolean now) throws IOException { + if (serverSettings == null) { + serverSettings = SettingsFrame.getDefaultSettings(); + } + if (now) { + writeFrame(serverSettings); + } else { + outputQ.put(serverSettings); + } + } + + String readUntil(String end) throws IOException { + int number = end.length(); + int found = 0; + StringBuilder sb = new StringBuilder(); + while (found < number) { + char expected = end.charAt(found); + int c = is.read(); + if (c == -1) { + throw new IOException("Connection closed"); + } + char c0 = (char) c; + sb.append(c0); + if (c0 != expected) { + found = 0; + continue; + } + found++; + } + return sb.toString(); + } + + private int getContentLength(String headers) { + return getIntHeader(headers, "Content-length"); + } + + private int getIntHeader(String headers, String name) { + String val = getHeader(headers, name); + if (val == null) { + return -1; + } + return Integer.parseInt(val); + } + + private String getHeader(String headers, String name) { + String headers1 = headers.toLowerCase(); // not efficient + name = CRLF + name.toLowerCase(); + int start = headers1.indexOf(name); + if (start == -1) { + return null; + } + start += 2; + int end = headers1.indexOf(CRLF, start); + String line = headers.substring(start, end); + start = line.indexOf(':'); + if (start == -1) { + return null; + } + return line.substring(start + 1).trim(); + } + + final static String CRLF = "\r\n"; + + String readHttp1Request() throws IOException { + String headers = readUntil(CRLF + CRLF); + int clen = getContentLength(headers); + // read the content. There shouldn't be content but .. + byte[] buf = new byte[clen]; + is.readNBytes(buf, 0, clen); + String body = new String(buf, "US-ASCII"); + return headers + body; + } + + void sendHttp1Response(int code, String msg, String... headers) throws IOException { + StringBuilder sb = new StringBuilder(); + sb.append("HTTP/1.1 ") + .append(code) + .append(' ') + .append(msg) + .append(CRLF); + int numheaders = headers.length; + for (int i = 0; i < numheaders; i += 2) { + sb.append(headers[i]) + .append(": ") + .append(headers[i + 1]) + .append(CRLF); + } + sb.append(CRLF); + String s = sb.toString(); + os.write(s.getBytes("US-ASCII")); + os.flush(); + } + + private void unexpectedFrame(Http2Frame frame) { + System.err.println("OOPS. Unexpected"); + assert false; + } + + final static ByteBuffer[] bbarray = new ByteBuffer[0]; + + // wrapper around a BlockingQueue that throws an exception when it's closed + // Each stream has one of these + + String getRequestBody(String request) { + int bodystart = request.indexOf(CRLF+CRLF); + String body; + if (bodystart == -1) + body = ""; + else + body = request.substring(bodystart+4); + return body; + } + + @SuppressWarnings({"rawtypes","unchecked"}) + void addRequestBodyToQueue(String body, Queue q) throws IOException { + ByteBuffer buf = ByteBuffer.wrap(body.getBytes(StandardCharsets.US_ASCII)); + DataFrame df = new DataFrame(); + df.streamid(1); // only used for primordial stream + df.setData(buf); + df.computeLength(); + df.setFlag(DataFrame.END_STREAM); + q.put(df); + } + + // window updates done in main reader thread because they may + // be used to unblock BodyOutputStreams waiting for WUPs + + HashMap> updaters = new HashMap<>(); + + void registerStreamWindowUpdater(int streamid, Consumer r) { + synchronized(updaters) { + updaters.put(streamid, r); + } + } + + int sendWindow = 64 * 1024 - 1; // connection level send window + + /** + * BodyOutputStreams call this to get the connection window first. + * + * @param amount + */ + synchronized void obtainConnectionWindow(int amount) throws InterruptedException { + while (amount > 0) { + int n = Math.min(amount, sendWindow); + amount -= n; + sendWindow -= n; + if (amount > 0) + wait(); + } + } + + synchronized void updateConnectionWindow(int amount) { + sendWindow += amount; + notifyAll(); + } + + // simplified output headers class. really just a type safe container + // for the hashmap. + + static class ResponseHeaders extends Http2Frame { + HttpHeadersImpl headers; + + ResponseHeaders(HttpHeadersImpl headers) { + this.headers = headers; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + throw new UnsupportedOperationException("Not supported ever!"); + } + + @Override + void computeLength() { + throw new UnsupportedOperationException("Not supported ever!"); + } + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/OutgoingPushPromise.java b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/OutgoingPushPromise.java new file mode 100644 index 00000000000..30654096437 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/OutgoingPushPromise.java @@ -0,0 +1,31 @@ +package java.net.http; + +import java.io.*; +import java.net.*; + +// will be converted to a PushPromiseFrame in the writeLoop +// a thread is then created to produce the DataFrames from the InputStream +class OutgoingPushPromise extends Http2Frame { + final HttpHeadersImpl headers; + final URI uri; + final InputStream is; + final int parentStream; // not the pushed streamid + + OutgoingPushPromise(int parentStream, URI uri, HttpHeadersImpl headers, InputStream is) { + this.uri = uri; + this.headers = headers; + this.is = is; + this.parentStream = parentStream; + } + + @Override + void readIncomingImpl(ByteBufferConsumer bc) throws IOException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + void computeLength() { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/PushHandler.java b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/PushHandler.java new file mode 100644 index 00000000000..c2797815543 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/PushHandler.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.net.http; + +import java.io.*; +import java.net.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.net.http.*; +import java.util.*; +import java.util.concurrent.*; + +public class PushHandler implements Http2Handler { + + final Path tempFile; + final int loops; + + public PushHandler(int file_size, int loops) throws Exception { + tempFile = TestUtil.getAFile(file_size); + this.loops = loops; + } + + int invocation = 0; + + public void handle(Http2TestExchange ee) { + try { + System.err.println ("Server: handle " + ee); + invocation++; + + if (ee.serverPushAllowed()) { + for (int i=0; i Date: Fri, 29 Apr 2016 16:57:57 -0700 Subject: [PATCH 204/222] 8153293: Preserve SORTED and DISTINCT characteristics for boxed() and asLongStream() operations Reviewed-by: psandoz --- .../java/util/stream/DoublePipeline.java | 30 +++++----- .../classes/java/util/stream/IntPipeline.java | 36 +++++------ .../java/util/stream/LongPipeline.java | 33 +++++----- .../util/stream/DoublePrimitiveOpsTests.java | 30 ++++++++++ .../util/stream/IntPrimitiveOpsTests.java | 60 +++++++++++++++++++ .../util/stream/LongPrimitiveOpsTests.java | 48 +++++++++++++++ 6 files changed, 189 insertions(+), 48 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/stream/DoublePipeline.java b/jdk/src/java.base/share/classes/java/util/stream/DoublePipeline.java index 56a5f57cc57..199a3d37f6a 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/DoublePipeline.java +++ b/jdk/src/java.base/share/classes/java/util/stream/DoublePipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,6 +167,19 @@ abstract class DoublePipeline return Nodes.doubleBuilder(exactSizeIfKnown); } + private Stream mapToObj(DoubleFunction mapper, int opFlags) { + return new ReferencePipeline.StatelessOp(this, StreamShape.DOUBLE_VALUE, opFlags) { + @Override + Sink opWrapSink(int flags, Sink sink) { + return new Sink.ChainedDouble(sink) { + @Override + public void accept(double t) { + downstream.accept(mapper.apply(t)); + } + }; + } + }; + } // DoubleStream @@ -184,7 +197,7 @@ abstract class DoublePipeline @Override public final Stream boxed() { - return mapToObj(Double::valueOf); + return mapToObj(Double::valueOf, 0); } @Override @@ -207,18 +220,7 @@ abstract class DoublePipeline @Override public final Stream mapToObj(DoubleFunction mapper) { Objects.requireNonNull(mapper); - return new ReferencePipeline.StatelessOp(this, StreamShape.DOUBLE_VALUE, - StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { - @Override - Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedDouble(sink) { - @Override - public void accept(double t) { - downstream.accept(mapper.apply(t)); - } - }; - } - }; + return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT); } @Override diff --git a/jdk/src/java.base/share/classes/java/util/stream/IntPipeline.java b/jdk/src/java.base/share/classes/java/util/stream/IntPipeline.java index 7cf0622ce89..fe7bac59b6e 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/IntPipeline.java +++ b/jdk/src/java.base/share/classes/java/util/stream/IntPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,6 +170,19 @@ abstract class IntPipeline return Nodes.intBuilder(exactSizeIfKnown); } + private Stream mapToObj(IntFunction mapper, int opFlags) { + return new ReferencePipeline.StatelessOp(this, StreamShape.INT_VALUE, opFlags) { + @Override + Sink opWrapSink(int flags, Sink sink) { + return new Sink.ChainedInt(sink) { + @Override + public void accept(int t) { + downstream.accept(mapper.apply(t)); + } + }; + } + }; + } // IntStream @@ -187,8 +200,7 @@ abstract class IntPipeline @Override public final LongStream asLongStream() { - return new LongPipeline.StatelessOp(this, StreamShape.INT_VALUE, - StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { + return new LongPipeline.StatelessOp(this, StreamShape.INT_VALUE, 0) { @Override Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @@ -203,8 +215,7 @@ abstract class IntPipeline @Override public final DoubleStream asDoubleStream() { - return new DoublePipeline.StatelessOp(this, StreamShape.INT_VALUE, - StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { + return new DoublePipeline.StatelessOp(this, StreamShape.INT_VALUE, 0) { @Override Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @@ -219,7 +230,7 @@ abstract class IntPipeline @Override public final Stream boxed() { - return mapToObj(Integer::valueOf); + return mapToObj(Integer::valueOf, 0); } @Override @@ -242,18 +253,7 @@ abstract class IntPipeline @Override public final Stream mapToObj(IntFunction mapper) { Objects.requireNonNull(mapper); - return new ReferencePipeline.StatelessOp(this, StreamShape.INT_VALUE, - StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { - @Override - Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { - @Override - public void accept(int t) { - downstream.accept(mapper.apply(t)); - } - }; - } - }; + return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT); } @Override diff --git a/jdk/src/java.base/share/classes/java/util/stream/LongPipeline.java b/jdk/src/java.base/share/classes/java/util/stream/LongPipeline.java index 19097b7e630..0d70b9707ca 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/LongPipeline.java +++ b/jdk/src/java.base/share/classes/java/util/stream/LongPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,6 +167,19 @@ abstract class LongPipeline return Nodes.longBuilder(exactSizeIfKnown); } + private Stream mapToObj(LongFunction mapper, int opFlags) { + return new ReferencePipeline.StatelessOp(this, StreamShape.LONG_VALUE, opFlags) { + @Override + Sink opWrapSink(int flags, Sink sink) { + return new Sink.ChainedLong(sink) { + @Override + public void accept(long t) { + downstream.accept(mapper.apply(t)); + } + }; + } + }; + } // LongStream @@ -184,8 +197,7 @@ abstract class LongPipeline @Override public final DoubleStream asDoubleStream() { - return new DoublePipeline.StatelessOp(this, StreamShape.LONG_VALUE, - StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { + return new DoublePipeline.StatelessOp(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { @@ -200,7 +212,7 @@ abstract class LongPipeline @Override public final Stream boxed() { - return mapToObj(Long::valueOf); + return mapToObj(Long::valueOf, 0); } @Override @@ -223,18 +235,7 @@ abstract class LongPipeline @Override public final Stream mapToObj(LongFunction mapper) { Objects.requireNonNull(mapper); - return new ReferencePipeline.StatelessOp(this, StreamShape.LONG_VALUE, - StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { - @Override - Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { - @Override - public void accept(long t) { - downstream.accept(mapper.apply(t)); - } - }; - } - }; + return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT); } @Override diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java index c476f18c624..5819d3f4c80 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java @@ -27,11 +27,18 @@ import org.testng.annotations.Test; import java.util.Arrays; import java.util.Random; +import java.util.Spliterator; import java.util.stream.DoubleStream; import java.util.stream.LongStream; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +/** + * @test + * @bug 8153293 + */ @Test public class DoublePrimitiveOpsTests { @@ -42,6 +49,13 @@ public class DoublePrimitiveOpsTests { assertEquals(sum, 1.0 + 2.0 + 3.0 + 4.0 + 5.0); } + public void testFlags() { + assertTrue(LongStream.range(1, 10).asDoubleStream().boxed().spliterator() + .hasCharacteristics(Spliterator.SORTED)); + assertFalse(DoubleStream.of(1, 10).boxed().spliterator() + .hasCharacteristics(Spliterator.SORTED)); + } + public void testToArray() { { double[] array = LongStream.range(1, 10).asDoubleStream().map(i -> i * 2).toArray(); @@ -72,6 +86,22 @@ public class DoublePrimitiveOpsTests { } } + public void testSortDistinct() { + { + double[] range = LongStream.range(0, 10).asDoubleStream().toArray(); + + assertEquals(LongStream.range(0, 10).asDoubleStream().sorted().distinct().toArray(), range); + assertEquals(LongStream.range(0, 10).asDoubleStream().parallel().sorted().distinct().toArray(), range); + + double[] data = {5, 3, 1, 1, 5, Double.NaN, 3, 9, Double.POSITIVE_INFINITY, + Double.NEGATIVE_INFINITY, 2, 9, 1, 0, 8, Double.NaN, -0.0}; + double[] expected = {Double.NEGATIVE_INFINITY, -0.0, 0, 1, 2, 3, 5, 8, 9, + Double.POSITIVE_INFINITY, Double.NaN}; + assertEquals(DoubleStream.of(data).sorted().distinct().toArray(), expected); + assertEquals(DoubleStream.of(data).parallel().sorted().distinct().toArray(), expected); + } + } + public void testSortSort() { Random r = new Random(); diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java index 1efc5fde987..1397d236b30 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java @@ -28,13 +28,21 @@ import org.testng.annotations.Test; import java.util.Arrays; import java.util.List; import java.util.Random; +import java.util.Spliterator; +import java.util.TreeSet; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.IntConsumer; import java.util.stream.Collectors; import java.util.stream.IntStream; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +/** + * @test + * @bug 8153293 + */ @Test public class IntPrimitiveOpsTests { @@ -85,6 +93,29 @@ public class IntPrimitiveOpsTests { assertEquals(sum, 15); } + public void testFlags() { + assertTrue(IntStream.range(1, 10).boxed().spliterator() + .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT)); + assertFalse(IntStream.of(1, 10).boxed().spliterator() + .hasCharacteristics(Spliterator.SORTED)); + assertFalse(IntStream.of(1, 10).boxed().spliterator() + .hasCharacteristics(Spliterator.DISTINCT)); + + assertTrue(IntStream.range(1, 10).asLongStream().spliterator() + .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT)); + assertFalse(IntStream.of(1, 10).asLongStream().spliterator() + .hasCharacteristics(Spliterator.SORTED)); + assertFalse(IntStream.of(1, 10).asLongStream().spliterator() + .hasCharacteristics(Spliterator.DISTINCT)); + + assertTrue(IntStream.range(1, 10).asDoubleStream().spliterator() + .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT)); + assertFalse(IntStream.of(1, 10).asDoubleStream().spliterator() + .hasCharacteristics(Spliterator.SORTED)); + assertFalse(IntStream.of(1, 10).asDoubleStream().spliterator() + .hasCharacteristics(Spliterator.DISTINCT)); + } + public void testToArray() { { int[] array = IntStream.range(1, 10).map(i -> i * 2).toArray(); @@ -115,6 +146,35 @@ public class IntPrimitiveOpsTests { } } + public void testSortDistinct() { + { + int[] range = IntStream.range(0, 10).toArray(); + + assertEquals(IntStream.range(0, 10).sorted().distinct().toArray(), range); + assertEquals(IntStream.range(0, 10).parallel().sorted().distinct().toArray(), range); + + int[] data = {5, 3, 1, 1, 5, 3, 9, 2, 9, 1, 0, 8}; + int[] expected = {0, 1, 2, 3, 5, 8, 9}; + assertEquals(IntStream.of(data).sorted().distinct().toArray(), expected); + assertEquals(IntStream.of(data).parallel().sorted().distinct().toArray(), expected); + } + + { + int[] input = new Random().ints(100, -10, 10).map(x -> x+Integer.MAX_VALUE).toArray(); + TreeSet longs = new TreeSet<>(); + for(int i : input) longs.add((long)i); + long[] expectedLongs = longs.stream().mapToLong(Long::longValue).toArray(); + assertEquals(IntStream.of(input).sorted().asLongStream().sorted().distinct().toArray(), + expectedLongs); + + TreeSet doubles = new TreeSet<>(); + for(int i : input) doubles.add((double)i); + double[] expectedDoubles = doubles.stream().mapToDouble(Double::doubleValue).toArray(); + assertEquals(IntStream.of(input).sorted().distinct().asDoubleStream() + .sorted().distinct().toArray(), expectedDoubles); + } + } + public void testSortSort() { Random r = new Random(); diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java index fc8fa2a6763..496a3542300 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java @@ -28,13 +28,21 @@ import org.testng.annotations.Test; import java.util.Arrays; import java.util.List; import java.util.Random; +import java.util.Spliterator; +import java.util.TreeSet; import java.util.concurrent.atomic.AtomicLong; import java.util.function.LongConsumer; import java.util.stream.Collectors; import java.util.stream.LongStream; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +/** + * @test + * @bug 8153293 + */ @Test public class LongPrimitiveOpsTests { @@ -85,6 +93,22 @@ public class LongPrimitiveOpsTests { assertEquals(sum, 15); } + public void testFlags() { + assertTrue(LongStream.range(1, 10).boxed().spliterator() + .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT)); + assertFalse(LongStream.of(1, 10).boxed().spliterator() + .hasCharacteristics(Spliterator.SORTED)); + assertFalse(LongStream.of(1, 10).boxed().spliterator() + .hasCharacteristics(Spliterator.DISTINCT)); + + assertTrue(LongStream.range(1, 10).asDoubleStream().spliterator() + .hasCharacteristics(Spliterator.SORTED)); + assertFalse(LongStream.range(1, 10).asDoubleStream().spliterator() + .hasCharacteristics(Spliterator.DISTINCT)); + assertFalse(LongStream.of(1, 10).asDoubleStream().spliterator() + .hasCharacteristics(Spliterator.SORTED)); + } + public void testToArray() { { long[] array = LongStream.range(1, 10).map(i -> i * 2).toArray(); @@ -115,6 +139,30 @@ public class LongPrimitiveOpsTests { } } + public void testSortDistinct() { + { + long[] range = LongStream.range(0, 10).toArray(); + + assertEquals(LongStream.range(0, 10).sorted().distinct().toArray(), range); + assertEquals(LongStream.range(0, 10).parallel().sorted().distinct().toArray(), range); + + long[] data = {5, 3, 1, 1, 5, 3, 9, 2, 9, 1, 0, 8}; + long[] expected = {0, 1, 2, 3, 5, 8, 9}; + assertEquals(LongStream.of(data).sorted().distinct().toArray(), expected); + assertEquals(LongStream.of(data).parallel().sorted().distinct().toArray(), expected); + } + + { + long[] input = new Random().longs(100, -10, 10).map(x -> x+Long.MAX_VALUE).toArray(); + + TreeSet doubles = new TreeSet<>(); + for(long i : input) doubles.add((double)i); + double[] expectedDoubles = doubles.stream().mapToDouble(Double::doubleValue).toArray(); + assertEquals(LongStream.of(input).sorted().distinct().asDoubleStream() + .sorted().distinct().toArray(), expectedDoubles); + } + } + public void testSortSort() { Random r = new Random(); From 53420d651623a13b682c87ae50a87f9b4b959cc5 Mon Sep 17 00:00:00 2001 From: "Tagir F. Valeev" Date: Fri, 29 Apr 2016 16:58:00 -0700 Subject: [PATCH 205/222] 8154387: Parallel unordered Stream.limit() tries to collect 128 elements even if limit is less Reviewed-by: psandoz --- .../java/util/stream/StreamSpliterators.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/stream/StreamSpliterators.java b/jdk/src/java.base/share/classes/java/util/stream/StreamSpliterators.java index 7e8d81150a8..cb92b2ebfad 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/StreamSpliterators.java +++ b/jdk/src/java.base/share/classes/java/util/stream/StreamSpliterators.java @@ -28,6 +28,7 @@ import java.util.Comparator; import java.util.Objects; import java.util.Spliterator; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicLong; import java.util.function.BooleanSupplier; import java.util.function.Consumer; @@ -905,6 +906,7 @@ class StreamSpliterators { // The spliterator to slice protected final T_SPLITR s; protected final boolean unlimited; + protected final int chunkSize; private final long skipThreshold; private final AtomicLong permits; @@ -912,6 +914,8 @@ class StreamSpliterators { this.s = s; this.unlimited = limit < 0; this.skipThreshold = limit >= 0 ? limit : 0; + this.chunkSize = limit >= 0 ? (int)Math.min(CHUNK_SIZE, + ((skip + limit) / AbstractTask.LEAF_TARGET) + 1) : CHUNK_SIZE; this.permits = new AtomicLong(limit >= 0 ? skip + limit : skip); } @@ -921,6 +925,7 @@ class StreamSpliterators { this.unlimited = parent.unlimited; this.permits = parent.permits; this.skipThreshold = parent.skipThreshold; + this.chunkSize = parent.chunkSize; } /** @@ -1029,13 +1034,13 @@ class StreamSpliterators { PermitStatus permitStatus; while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) { if (permitStatus == PermitStatus.MAYBE_MORE) { - // Optimistically traverse elements up to a threshold of CHUNK_SIZE + // Optimistically traverse elements up to a threshold of chunkSize if (sb == null) - sb = new ArrayBuffer.OfRef<>(CHUNK_SIZE); + sb = new ArrayBuffer.OfRef<>(chunkSize); else sb.reset(); long permitsRequested = 0; - do { } while (s.tryAdvance(sb) && ++permitsRequested < CHUNK_SIZE); + do { } while (s.tryAdvance(sb) && ++permitsRequested < chunkSize); if (permitsRequested == 0) return; sb.forEach(action, acquirePermits(permitsRequested)); @@ -1102,15 +1107,15 @@ class StreamSpliterators { PermitStatus permitStatus; while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) { if (permitStatus == PermitStatus.MAYBE_MORE) { - // Optimistically traverse elements up to a threshold of CHUNK_SIZE + // Optimistically traverse elements up to a threshold of chunkSize if (sb == null) - sb = bufferCreate(CHUNK_SIZE); + sb = bufferCreate(chunkSize); else sb.reset(); @SuppressWarnings("unchecked") T_CONS sbc = (T_CONS) sb; long permitsRequested = 0; - do { } while (s.tryAdvance(sbc) && ++permitsRequested < CHUNK_SIZE); + do { } while (s.tryAdvance(sbc) && ++permitsRequested < chunkSize); if (permitsRequested == 0) return; sb.forEach(action, acquirePermits(permitsRequested)); From ce05d52251d595196671d6f932111390a9435868 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Sat, 30 Apr 2016 16:08:48 -0700 Subject: [PATCH 206/222] 8155792: Add @jls citations to java.lang.String Reviewed-by: alanb --- jdk/src/java.base/share/classes/java/lang/String.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/lang/String.java b/jdk/src/java.base/share/classes/java/lang/String.java index 64299b92337..33222a586b5 100644 --- a/jdk/src/java.base/share/classes/java/lang/String.java +++ b/jdk/src/java.base/share/classes/java/lang/String.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,6 +117,7 @@ import jdk.internal.vm.annotation.Stable; * @see java.lang.StringBuilder * @see java.nio.charset.Charset * @since 1.0 + * @jls 15.18.1 String Concatenation Operator + */ public final class String @@ -2979,6 +2980,7 @@ public final class String * * @return a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. + * @jls 3.10.5 String Literals */ public native String intern(); From 2f5a588d257a72c68968d1b70acb05dd1036867d Mon Sep 17 00:00:00 2001 From: Srikanth Adayapalam Date: Mon, 2 May 2016 10:11:24 +0530 Subject: [PATCH 207/222] 8155028: javac crashes in silly do-while loop Compiler should short circuit code generation for unreachable code. Reviewed-by: mcimadamore --- .../classes/com/sun/tools/javac/jvm/Gen.java | 20 +++-- .../test/tools/javac/UnreachableLoopCond.java | 85 +++++++++++++++++++ 2 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 langtools/test/tools/javac/UnreachableLoopCond.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index 5de84f0ab59..ea30fe09a06 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -1086,17 +1086,19 @@ public class Gen extends JCTree.Visitor { genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET); code.resolve(loopEnv.info.cont); genStats(step, loopEnv); - CondItem c; - if (cond != null) { - code.statBegin(cond.pos); + if (code.isAlive()) { + CondItem c; + if (cond != null) { + code.statBegin(cond.pos); + Assert.check(code.state.stacksize == 0); + c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER); + } else { + c = items.makeCondItem(goto_); + } + code.resolve(c.jumpTrue(), startpc); Assert.check(code.state.stacksize == 0); - c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER); - } else { - c = items.makeCondItem(goto_); + code.resolve(c.falseJumps); } - code.resolve(c.jumpTrue(), startpc); - Assert.check(code.state.stacksize == 0); - code.resolve(c.falseJumps); } Chain exit = loopEnv.info.exit; if (exit != null) { diff --git a/langtools/test/tools/javac/UnreachableLoopCond.java b/langtools/test/tools/javac/UnreachableLoopCond.java new file mode 100644 index 00000000000..17bfb201c25 --- /dev/null +++ b/langtools/test/tools/javac/UnreachableLoopCond.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 8155028 + * @summary javac crashes in silly do-while loop + * @compile UnreachableLoopCond.java + */ + +class UnreachableLoopCond { + + public void foo() { + Integer i = 100; + do { + return; + } while (i++ < 10); + } + + public void goo() { + Integer i = 100; + do { + break; + } while (i++ < 10); + } + + public void zoo() { + Integer i = 100; + do { + throw new RuntimeException(); + } while (i++ < 10); + } + + public void loo() { + Integer i = 100; + Integer j = 100; + do { + do { + return; + } while (i++ < 10); + } while (j++ < 10); + } + + public void moo() { + Integer i = 100; + do { + if (true) { + return; + } else { + return; + } + } while (i++ < 10); + } + + public void moo(boolean cond) { + Integer i = 100; + do { + if (cond) { + return; + } else { + return; + } + } while (i++ < 10); + } +} From 8ca267abe352314dcebeba40ecd00d700ce472f6 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 2 May 2016 06:43:44 +0200 Subject: [PATCH 208/222] 8050993: There is no record for condition in ternary operator in LineNumberTable Make sure there is an entry in the LineNumberTable for the condition of the ternary operator Co-authored-by: Andrey Nazarov Reviewed-by: jjg --- .../classes/com/sun/tools/javac/jvm/Gen.java | 1 + .../LineNumberTable/LineNumberTestBase.java | 2 +- .../attributes/LineNumberTable/T8050993.java | 53 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 langtools/test/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index ea30fe09a06..4941b17c096 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -1649,6 +1649,7 @@ public class Gen extends JCTree.Visitor { public void visitConditional(JCConditional tree) { Chain thenExit = null; + code.statBegin(tree.cond.pos); CondItem c = genCond(tree.cond, CRT_FLOW_CONTROLLER); Chain elseChain = c.jumpFalse(); if (!c.isFalse()) { diff --git a/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java b/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java index eabf5bd5e75..93e9c80d966 100644 --- a/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java +++ b/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java @@ -191,7 +191,7 @@ public class LineNumberTestBase extends TestBase { CONDITION("int res = \n" + "testField == 2 ?\n" + "10\n" + - ":9;", 1, 3, 4), // see issue https://bugs.openjdk.java.net/browse/JDK-8050993 + ":9;", 2, 3, 4), TRY("try{\n" + " --testField;\n" + "}\n" + diff --git a/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java b/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java new file mode 100644 index 00000000000..53ba5fe2366 --- /dev/null +++ b/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java @@ -0,0 +1,53 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8050993 + * @summary Verify that the condition in the conditional lexpression gets a LineNumberTable entry + * @modules jdk.jdeps/com.sun.tools.classfile + * @compile -g T8050993.java + * @run main T8050993 + */ + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import com.sun.tools.classfile.*; + +public class T8050993 { + public static void main(String[] args) throws IOException, ConstantPoolException { + ClassFile someTestIn = ClassFile.read(T8050993.class.getResourceAsStream("T8050993.class")); + Set expectedLineNumbers = new HashSet<>(Arrays.asList(48, 49, 46, 47)); + for (Method m : someTestIn.methods) { + if ("method".equals(m.getName(someTestIn.constant_pool))) { + Code_attribute code_attribute = (Code_attribute) m.attributes.get(Attribute.Code); + for (Attribute at : code_attribute.attributes) { + if (Attribute.LineNumberTable.equals(at.getName(someTestIn.constant_pool))) { + LineNumberTable_attribute att = (LineNumberTable_attribute) at; + Set actualLinesNumbers = Arrays.stream(att.line_number_table) + .map(e -> e.line_number) + .collect(Collectors.toSet()); + if (!Objects.equals(expectedLineNumbers, actualLinesNumbers)) { + throw new AssertionError("Expected LineNumber entries not found;" + + "actual=" + actualLinesNumbers + ";" + + "expected=" + expectedLineNumbers); + } + } + } + } + } + } + + public static int field; + + public static String method() { + String s = + field % 2 == 0 ? + "true" + field : + "false" + field; + return s; + } + +} From d7af112d8da0012955a55d210ba63c65bb1c456d Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 2 May 2016 12:57:05 +0200 Subject: [PATCH 209/222] 8155816: langtools/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java test broken Correcting expected line numbers Reviewed-by: alundblad --- .../javac/classfiles/attributes/LineNumberTable/T8050993.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java b/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java index 53ba5fe2366..2c2e8fcd6a3 100644 --- a/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java +++ b/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java @@ -19,7 +19,7 @@ import com.sun.tools.classfile.*; public class T8050993 { public static void main(String[] args) throws IOException, ConstantPoolException { ClassFile someTestIn = ClassFile.read(T8050993.class.getResourceAsStream("T8050993.class")); - Set expectedLineNumbers = new HashSet<>(Arrays.asList(48, 49, 46, 47)); + Set expectedLineNumbers = new HashSet<>(Arrays.asList(49, 50, 47, 48)); for (Method m : someTestIn.methods) { if ("method".equals(m.getName(someTestIn.constant_pool))) { Code_attribute code_attribute = (Code_attribute) m.attributes.get(Attribute.Code); From 0dc92a6e8ca34ae92a85db7d76a06f6db77c5a21 Mon Sep 17 00:00:00 2001 From: Matthias Klose Date: Mon, 2 May 2016 15:05:54 +0200 Subject: [PATCH 210/222] 8155821: Typo for s390x for HOTSPOT__CPU_DEFINE Reviewed-by: erikj --- common/autoconf/generated-configure.sh | 8 ++++---- common/autoconf/platform.m4 | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 9563705cdcb..a2d42fb30b8 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -1224,9 +1224,9 @@ with_lcms with_dxsdk with_dxsdk_lib with_dxsdk_include -enable_jtreg_failure_handler enable_new_hotspot_build enable_hotspot_test_in_build +enable_jtreg_failure_handler with_num_cores with_memory_size with_jobs @@ -5070,7 +5070,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1460963400 +DATE_WHEN_GENERATED=1462194239 ############################################################################### # @@ -15492,7 +15492,7 @@ $as_echo "$COMPILE_TYPE" >&6; } HOTSPOT_TARGET_CPU_DEFINE=PPC32 elif test "x$OPENJDK_TARGET_CPU" = xs390; then HOTSPOT_TARGET_CPU_DEFINE=S390 - elif test "x$OPENJDK_TARGET_CPU" = ss390x; then + elif test "x$OPENJDK_TARGET_CPU" = xs390x; then HOTSPOT_TARGET_CPU_DEFINE=S390 fi @@ -15648,7 +15648,7 @@ $as_echo "$COMPILE_TYPE" >&6; } HOTSPOT_BUILD_CPU_DEFINE=PPC32 elif test "x$OPENJDK_BUILD_CPU" = xs390; then HOTSPOT_BUILD_CPU_DEFINE=S390 - elif test "x$OPENJDK_BUILD_CPU" = ss390x; then + elif test "x$OPENJDK_BUILD_CPU" = xs390x; then HOTSPOT_BUILD_CPU_DEFINE=S390 fi diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index deaf22ed169..2e99c452694 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -435,7 +435,7 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], HOTSPOT_$1_CPU_DEFINE=PPC32 elif test "x$OPENJDK_$1_CPU" = xs390; then HOTSPOT_$1_CPU_DEFINE=S390 - elif test "x$OPENJDK_$1_CPU" = ss390x; then + elif test "x$OPENJDK_$1_CPU" = xs390x; then HOTSPOT_$1_CPU_DEFINE=S390 fi AC_SUBST(HOTSPOT_$1_CPU_DEFINE) From c7ff5269963eaa1745b97ebc481365ecce544766 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Mon, 2 May 2016 08:54:14 -0700 Subject: [PATCH 211/222] 8139832: JShell API: Diag constructor should not be exposed and fix typo Reviewed-by: jlahoda --- .../src/jdk.jshell/share/classes/jdk/jshell/Diag.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java index 396396dec2a..c24578b3369 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java @@ -35,13 +35,19 @@ import javax.tools.Diagnostic; public abstract class Diag { // Simplified view on compiler Diagnostic. + /** + * In-package creation only. + */ + Diag() { + } + /** * Used to signal that no position is available. */ public final static long NOPOS = Diagnostic.NOPOS; /** - * Is this diagnostic and error (as opposed to a warning or note) + * Is this diagnostic an error (as opposed to a warning or note) * @return true if this diagnostic is an error */ public abstract boolean isError(); From 7eb46a2e0f7200ad569e36db95aac9439cfd1e47 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 2 May 2016 17:54:37 +0200 Subject: [PATCH 212/222] 8155824: JDK build should tune down small apps more aggressively Reviewed-by: erikj --- common/autoconf/boot-jdk.m4 | 1 + common/autoconf/generated-configure.sh | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4 index b27cb9a0b70..f264c510fde 100644 --- a/common/autoconf/boot-jdk.m4 +++ b/common/autoconf/boot-jdk.m4 @@ -397,6 +397,7 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], ADD_JVM_ARG_IF_OK([-XX:+UseSerialGC],boot_jdk_jvmargs_small,[$JAVA]) ADD_JVM_ARG_IF_OK([-Xms32M],boot_jdk_jvmargs_small,[$JAVA]) ADD_JVM_ARG_IF_OK([-Xmx512M],boot_jdk_jvmargs_small,[$JAVA]) + ADD_JVM_ARG_IF_OK([-XX:TieredStopAtLevel=1],boot_jdk_jvmargs_small,[$JAVA]) AC_MSG_RESULT([$boot_jdk_jvmargs_small]) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index a2d42fb30b8..f68d8437643 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -5070,7 +5070,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1462194239 +DATE_WHEN_GENERATED=1462204427 ############################################################################### # @@ -64282,6 +64282,21 @@ $as_echo_n "checking flags for boot jdk java command for small workloads... " >& fi + $ECHO "Check if jvm arg is ok: -XX:TieredStopAtLevel=1" >&5 + $ECHO "Command: $JAVA -XX:TieredStopAtLevel=1 -version" >&5 + OUTPUT=`$JAVA -XX:TieredStopAtLevel=1 -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -XX:TieredStopAtLevel=1" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_small" >&5 $as_echo "$boot_jdk_jvmargs_small" >&6; } From 46109cd2041acc76327bace37a08c2b359ed9383 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 2 May 2016 12:44:31 -0700 Subject: [PATCH 213/222] 8155784: Build failure on Linux arm64 Reviewed-by: flar, serb --- .../unix/native/libawt_xawt/awt/awt_InputMethod.c | 1 + .../java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c index e4388cd64a4..2dc59c2c77c 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "awt.h" diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c index 6a188fb3598..060b082e53b 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c @@ -2547,14 +2547,14 @@ static jobject get_string_property(JNIEnv *env, GtkSettings* settings, static jobject get_integer_property(JNIEnv *env, GtkSettings* settings, const gchar* key) { - gint intval = NULL; + gint intval = 0; (*fp_g_object_get)(settings, key, &intval, NULL); return create_Integer(env, intval); } static jobject get_boolean_property(JNIEnv *env, GtkSettings* settings, const gchar* key) { - gint intval = NULL; + gint intval = 0; (*fp_g_object_get)(settings, key, &intval, NULL); return create_Boolean(env, intval); } From 4b69b86a7f2e4ed4b98d6eeda635b73207034c3f Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Mon, 2 May 2016 13:05:43 -0700 Subject: [PATCH 214/222] 8155859: Problem list tools/pack200/Pack200Props.java Reviewed-by: rriggs --- jdk/test/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 696c9cd270f..f3434f35be4 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -319,6 +319,8 @@ tools/pack200/Pack200Test.java 8059906,8151901 tools/launcher/FXLauncherTest.java 8068049 linux-all,macosx-all +tools/pack200/Pack200Props.java 8155857 generic-all + ############################################################################ # jdk_jdi From 5950e361a250cc4e11943b44fc065479bfb80629 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Mon, 2 May 2016 15:01:54 -0700 Subject: [PATCH 215/222] 8154578: Drop residual use of addReads from javadoc Reviewed-by: alanb, jjg --- .../toolkit/taglets/TagletManager.java | 22 ----------------- .../com/sun/tools/javadoc/DocletInvoker.java | 24 ------------------- .../toolkit/taglets/TagletManager.java | 22 ----------------- .../jdk/javadoc/internal/tool/Start.java | 23 ------------------ 4 files changed, 91 deletions(-) diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/TagletManager.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/TagletManager.java index bd4ff763147..1b43a69ae06 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/TagletManager.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/TagletManager.java @@ -242,7 +242,6 @@ public class TagletManager { } customTagClass = tagClassLoader.loadClass(classname); - ensureReadable(customTagClass); Method meth = customTagClass.getMethod("register", Map.class); @@ -269,27 +268,6 @@ public class TagletManager { } - /** - * Ensures that the module of the given class is readable to this - * module. - * @param targetClass class in module to be made readable - */ - private void ensureReadable(Class targetClass) { - try { - Method getModuleMethod = Class.class.getMethod("getModule"); - Object thisModule = getModuleMethod.invoke(this.getClass()); - Object targetModule = getModuleMethod.invoke(targetClass); - - Class moduleClass = getModuleMethod.getReturnType(); - Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass); - addReadsMethod.invoke(thisModule, targetModule); - } catch (NoSuchMethodException e) { - // ignore - } catch (Exception e) { - throw new InternalError(e); - } - } - /** * Export javadoc internal API to the unnamed module for a classloader. * This is to support continued use of existing non-standard doclets that diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java index f41edba705a..91e333e8ccb 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java @@ -102,7 +102,6 @@ public class DocletInvoker { this.apiMode = apiMode; this.exportInternalAPI = exportInternalAPI; // for backdoor use by standard doclet for taglets - ensureReadable(docletClass); // this may not be soon enough if the class has already been loaded if (exportInternalAPI) { exportInternalAPI(docletClass.getClassLoader()); @@ -149,8 +148,6 @@ public class DocletInvoker { messager.exit(); } docletClass = dc; - - ensureReadable(docletClass); } /* @@ -361,27 +358,6 @@ public class DocletInvoker { } } - /** - * Ensures that the module of the given class is readable to this - * module. - * @param targetClass class in module to be made readable - */ - private void ensureReadable(Class targetClass) { - try { - Method getModuleMethod = Class.class.getMethod("getModule"); - Object thisModule = getModuleMethod.invoke(this.getClass()); - Object targetModule = getModuleMethod.invoke(targetClass); - - Class moduleClass = getModuleMethod.getReturnType(); - Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass); - addReadsMethod.invoke(thisModule, targetModule); - } catch (NoSuchMethodException e) { - // ignore - } catch (Exception e) { - throw new InternalError(e); - } - } - /** * Export javadoc internal API to the unnamed module for a classloader. * This is to support continued use of existing non-standard doclets that diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java index 5b354316a11..ec809050f3c 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java @@ -246,7 +246,6 @@ public class TagletManager { } tagClassLoader = fileManager.getClassLoader(TAGLET_PATH); Class customTagClass = tagClassLoader.loadClass(classname); - ensureReadable(customTagClass); Object instance = customTagClass.newInstance(); Taglet newLegacy = new UserTaglet((jdk.javadoc.doclet.taglet.Taglet)instance); String tname = newLegacy.getName(); @@ -261,27 +260,6 @@ public class TagletManager { } } - /** - * Ensures that the module of the given class is readable to this - * module. - * @param targetClass class in module to be made readable - */ - private void ensureReadable(Class targetClass) { - try { - Method getModuleMethod = Class.class.getMethod("getModule"); - Object thisModule = getModuleMethod.invoke(this.getClass()); - Object targetModule = getModuleMethod.invoke(targetClass); - - Class moduleClass = getModuleMethod.getReturnType(); - Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass); - addReadsMethod.invoke(thisModule, targetModule); - } catch (NoSuchMethodException e) { - // ignore - } catch (Exception e) { - throw new InternalError(e.toString()); - } - } - /** * Add a new SimpleTaglet. If this tag already exists * and the header passed as an argument is null, move tag to the back of the diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java index f281ee43a17..d998e077663 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java @@ -330,27 +330,6 @@ public class Start extends ToolOption.Helper { return !failed; } - /** - * Ensures that the module of the given class is readable to this - * module. - * @param targetClass class in module to be made readable - */ - private void ensureReadable(Class targetClass) { - try { - Method getModuleMethod = Class.class.getMethod("getModule"); - Object thisModule = getModuleMethod.invoke(this.getClass()); - Object targetModule = getModuleMethod.invoke(targetClass); - - Class moduleClass = getModuleMethod.getReturnType(); - Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass); - addReadsMethod.invoke(thisModule, targetModule); - } catch (NoSuchMethodException e) { - // ignore - } catch (Exception e) { - throw new InternalError(e); - } - } - /** * Main program - internal */ @@ -550,7 +529,6 @@ public class Start extends ToolOption.Helper { } try { Class klass = cl.loadClass(userDocletName); - ensureReadable(klass); return klass; } catch (ClassNotFoundException cnfe) { error("main.doclet_class_not_found", userDocletName); @@ -601,7 +579,6 @@ public class Start extends ToolOption.Helper { for (String tagletName : tagletNames) { try { Class klass = cl.loadClass(tagletName); - ensureReadable(klass); if (com.sun.tools.doclets.Taglet.class.isAssignableFrom(klass)) { return true; } From 325a065aff50274aa3eaf630d380e42ceb513e89 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Mon, 2 May 2016 16:17:39 -0700 Subject: [PATCH 216/222] 8155774: move code from ModuleTestBase to toolbox Reviewed-by: ksrini, jlahoda --- .../AbstractOrInnerClassServiceImplTest.java | 6 +- .../tools/javac/modules/AddLimitMods.java | 6 +- .../tools/javac/modules/AddReadsTest.java | 12 +- .../javac/modules/AnnotationProcessing.java | 8 +- .../AnnotationProcessorsInModulesTest.java | 8 +- .../tools/javac/modules/AutomaticModules.java | 6 +- .../javac/modules/DoclintOtherModules.java | 2 +- .../javac/modules/DuplicateClassTest.java | 2 +- .../test/tools/javac/modules/EdgeCases.java | 14 +- .../test/tools/javac/modules/GraphsTest.java | 22 +-- .../tools/javac/modules/HelloWorldTest.java | 8 +- .../test/tools/javac/modules/MOptionTest.java | 8 +- .../tools/javac/modules/ModuleFinderTest.java | 2 +- .../tools/javac/modules/ModuleInfoTest.java | 26 ++-- .../javac/modules/ModuleInfoTreeAccess.java | 2 +- .../tools/javac/modules/ModulePathTest.java | 50 +++---- .../javac/modules/ModuleSourcePathTest.java | 36 ++--- .../tools/javac/modules/ModuleTestBase.java | 127 ++---------------- .../modules/ModulesAndClassPathTest.java | 8 +- .../javac/modules/MultiModuleModeTest.java | 10 +- .../modules/NPECompilingModuleInfoTest.java | 2 +- .../tools/javac/modules/NPEEmptyFileTest.java | 2 +- .../tools/javac/modules/OutputDirTest.java | 10 +- .../javac/modules/PackageConflictTest.java | 45 ++++--- .../javac/modules/PackageMultipleModules.java | 2 +- .../javac/modules/PluginsInModulesTest.java | 2 +- .../tools/javac/modules/ProvidesTest.java | 36 ++--- .../tools/javac/modules/QueryBeforeEnter.java | 10 +- .../modules/RepeatedUsesAndProvidesTest.java | 4 +- .../modules/ReportNonExistentPackageTest.java | 6 +- .../javac/modules/RequiresPublicTest.java | 8 +- .../test/tools/javac/modules/ResolveTest.java | 16 +-- .../ServiceInStaticClassErrorTest.java | 2 +- ...rviceProvidedButNotExportedOrUsedTest.java | 4 +- .../javac/modules/SingleModuleModeTest.java | 10 +- .../tools/javac/modules/SubpackageTest.java | 4 +- .../javac/modules/UpgradeModulePathTest.java | 51 +++---- .../test/tools/javac/modules/UsesTest.java | 33 ++--- .../test/tools/javac/modules/XModuleTest.java | 30 +++-- .../test/tools/lib/toolbox/JavacTask.java | 32 +++++ .../test/tools/lib/toolbox/ModuleBuilder.java | 111 +++++++++++++++ .../test/tools/lib/toolbox/TestRunner.java | 25 ++-- langtools/test/tools/lib/toolbox/ToolBox.java | 32 ++++- 43 files changed, 455 insertions(+), 385 deletions(-) create mode 100644 langtools/test/tools/lib/toolbox/ModuleBuilder.java diff --git a/langtools/test/tools/javac/modules/AbstractOrInnerClassServiceImplTest.java b/langtools/test/tools/javac/modules/AbstractOrInnerClassServiceImplTest.java index c4f3b84d2cb..d2b24764ce3 100644 --- a/langtools/test/tools/javac/modules/AbstractOrInnerClassServiceImplTest.java +++ b/langtools/test/tools/javac/modules/AbstractOrInnerClassServiceImplTest.java @@ -47,7 +47,7 @@ public class AbstractOrInnerClassServiceImplTest extends ModuleTestBase { } @Test - void testAbstractServiceImpl(Path base) throws Exception { + public void testAbstractServiceImpl(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.Service with p2.Impl; }", @@ -68,7 +68,7 @@ public class AbstractOrInnerClassServiceImplTest extends ModuleTestBase { } @Test - void testInnerClassServiceImpl(Path base) throws Exception { + public void testInnerClassServiceImpl(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.Service with p2.Outer.Inner; }", @@ -89,7 +89,7 @@ public class AbstractOrInnerClassServiceImplTest extends ModuleTestBase { } @Test - void testInnerInterfaceServiceImpl(Path base) throws Exception { + public void testInnerInterfaceServiceImpl(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.Service with p2.Outer.Inner; }", diff --git a/langtools/test/tools/javac/modules/AddLimitMods.java b/langtools/test/tools/javac/modules/AddLimitMods.java index 9df3b221fb5..e5d1c920fd8 100644 --- a/langtools/test/tools/javac/modules/AddLimitMods.java +++ b/langtools/test/tools/javac/modules/AddLimitMods.java @@ -79,7 +79,7 @@ public class AddLimitMods extends ModuleTestBase { } @Test - void testManual(Path base) throws Exception { + public void testManual(Path base) throws Exception { Path moduleSrc = base.resolve("module-src"); Path m1 = moduleSrc.resolve("m1"); @@ -176,7 +176,7 @@ public class AddLimitMods extends ModuleTestBase { } @Test - void testAllModulePath(Path base) throws Exception { + public void testAllModulePath(Path base) throws Exception { if (Files.isDirectory(base)) tb.cleanDirectory(base); @@ -284,7 +284,7 @@ public class AddLimitMods extends ModuleTestBase { } @Test - void testRuntime2Compile(Path base) throws Exception { + public void testRuntime2Compile(Path base) throws Exception { Path classpathSrc = base.resolve("classpath-src"); Path classpathOut = base.resolve("classpath-out"); diff --git a/langtools/test/tools/javac/modules/AddReadsTest.java b/langtools/test/tools/javac/modules/AddReadsTest.java index be91ed358c1..2c3c6c66e3b 100644 --- a/langtools/test/tools/javac/modules/AddReadsTest.java +++ b/langtools/test/tools/javac/modules/AddReadsTest.java @@ -58,7 +58,7 @@ public class AddReadsTest extends ModuleTestBase { } @Test - void testAddReads(Path base) throws Exception { + public void testAddReads(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeJavaFiles(src_m1, @@ -150,7 +150,7 @@ public class AddReadsTest extends ModuleTestBase { } @Test - void testAddReadsUnnamedModule(Path base) throws Exception { + public void testAddReadsUnnamedModule(Path base) throws Exception { Path jar = prepareTestJar(base); Path moduleSrc = base.resolve("module-src"); @@ -175,7 +175,7 @@ public class AddReadsTest extends ModuleTestBase { } @Test - void testAddReadsUnnamedModulePackageConflict(Path base) throws Exception { + public void testAddReadsUnnamedModulePackageConflict(Path base) throws Exception { Path jar = prepareTestJar(base); Path moduleSrc = base.resolve("module-src"); @@ -202,7 +202,7 @@ public class AddReadsTest extends ModuleTestBase { } @Test - void testAddReadsUnnamedToJavaBase(Path base) throws Exception { + public void testAddReadsUnnamedToJavaBase(Path base) throws Exception { Path jar = prepareTestJar(base); Path src = base.resolve("src"); Path classes = base.resolve("classes"); @@ -223,7 +223,7 @@ public class AddReadsTest extends ModuleTestBase { } @Test - void testAddReadsToJavaBase(Path base) throws Exception { + public void testAddReadsToJavaBase(Path base) throws Exception { Path src = base.resolve("src"); Path classes = base.resolve("classes"); @@ -275,7 +275,7 @@ public class AddReadsTest extends ModuleTestBase { } @Test - void testX(Path base) throws Exception { + public void testX(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeJavaFiles(src_m1, diff --git a/langtools/test/tools/javac/modules/AnnotationProcessing.java b/langtools/test/tools/javac/modules/AnnotationProcessing.java index d344503cbb6..9fa9e082d37 100644 --- a/langtools/test/tools/javac/modules/AnnotationProcessing.java +++ b/langtools/test/tools/javac/modules/AnnotationProcessing.java @@ -68,7 +68,7 @@ public class AnnotationProcessing extends ModuleTestBase { } @Test - void testAPSingleModule(Path base) throws Exception { + public void testAPSingleModule(Path base) throws Exception { Path moduleSrc = base.resolve("module-src"); Path m1 = moduleSrc.resolve("m1"); @@ -95,7 +95,7 @@ public class AnnotationProcessing extends ModuleTestBase { } @Test - void testAPMultiModule(Path base) throws Exception { + public void testAPMultiModule(Path base) throws Exception { Path moduleSrc = base.resolve("module-src"); Path m1 = moduleSrc.resolve("m1"); Path m2 = moduleSrc.resolve("m2"); @@ -196,7 +196,7 @@ public class AnnotationProcessing extends ModuleTestBase { } @Test - void testVerifyUsesProvides(Path base) throws Exception { + public void testVerifyUsesProvides(Path base) throws Exception { Path moduleSrc = base.resolve("module-src"); Path m1 = moduleSrc.resolve("m1"); @@ -254,7 +254,7 @@ public class AnnotationProcessing extends ModuleTestBase { } @Test - void testPackageNoModule(Path base) throws Exception { + public void testPackageNoModule(Path base) throws Exception { Path src = base.resolve("src"); Path classes = base.resolve("classes"); diff --git a/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java b/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java index cad93dba93f..1fe3a769ff7 100644 --- a/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java +++ b/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java @@ -156,7 +156,7 @@ public class AnnotationProcessorsInModulesTest extends ModuleTestBase { Path classes; @Test - void testUseOnlyOneProcessor(Path base) throws Exception { + public void testUseOnlyOneProcessor(Path base) throws Exception { initialization(base); String log = new JavacTask(tb) .options("-processormodulepath", processorCompiledModules.toString(), @@ -172,7 +172,7 @@ public class AnnotationProcessorsInModulesTest extends ModuleTestBase { } @Test - void testAnnotationProcessorExecutionOrder(Path base) throws Exception { + public void testAnnotationProcessorExecutionOrder(Path base) throws Exception { initialization(base); List log = new JavacTask(tb) .options("-processormodulepath", processorCompiledModules.toString(), @@ -202,7 +202,7 @@ public class AnnotationProcessorsInModulesTest extends ModuleTestBase { } @Test - void testErrorOutputIfOneProcessorNameIsIncorrect(Path base) throws Exception { + public void testErrorOutputIfOneProcessorNameIsIncorrect(Path base) throws Exception { initialization(base); String log = new JavacTask(tb) .options("-XDrawDiagnostics", "-processormodulepath", processorCompiledModules.toString(), @@ -218,7 +218,7 @@ public class AnnotationProcessorsInModulesTest extends ModuleTestBase { } @Test - void testOptionsExclusion(Path base) throws Exception { + public void testOptionsExclusion(Path base) throws Exception { initialization(base); List log = new JavacTask(tb) .options("-XDrawDiagnostics", "-processormodulepath", processorCompiledModules.toString(), diff --git a/langtools/test/tools/javac/modules/AutomaticModules.java b/langtools/test/tools/javac/modules/AutomaticModules.java index ba4d4401bd3..375d7907f11 100644 --- a/langtools/test/tools/javac/modules/AutomaticModules.java +++ b/langtools/test/tools/javac/modules/AutomaticModules.java @@ -48,7 +48,7 @@ public class AutomaticModules extends ModuleTestBase { } @Test - void testSimple(Path base) throws Exception { + public void testSimple(Path base) throws Exception { Path legacySrc = base.resolve("legacy-src"); tb.writeJavaFiles(legacySrc, "package api; import java.awt.event.ActionListener; public abstract class Api implements ActionListener {}"); @@ -98,7 +98,7 @@ public class AutomaticModules extends ModuleTestBase { } @Test - void testUnnamedModule(Path base) throws Exception { + public void testUnnamedModule(Path base) throws Exception { Path legacySrc = base.resolve("legacy-src"); tb.writeJavaFiles(legacySrc, "package api; public abstract class Api { public void run(CharSequence str) { } private void run(base.Base base) { } }", @@ -156,7 +156,7 @@ public class AutomaticModules extends ModuleTestBase { } @Test - void testModuleInfoFromClassFileDependsOnAutomatic(Path base) throws Exception { + public void testModuleInfoFromClassFileDependsOnAutomatic(Path base) throws Exception { Path automaticSrc = base.resolve("automaticSrc"); tb.writeJavaFiles(automaticSrc, "package api; public class Api {}"); Path automaticClasses = base.resolve("automaticClasses"); diff --git a/langtools/test/tools/javac/modules/DoclintOtherModules.java b/langtools/test/tools/javac/modules/DoclintOtherModules.java index 3c5108a41f1..cd89636f869 100644 --- a/langtools/test/tools/javac/modules/DoclintOtherModules.java +++ b/langtools/test/tools/javac/modules/DoclintOtherModules.java @@ -47,7 +47,7 @@ public class DoclintOtherModules extends ModuleTestBase { } @Test - void testSimple(Path base) throws Exception { + public void testSimple(Path base) throws Exception { Path src = base.resolve("src"); Path m1 = src.resolve("m1"); Path m2 = src.resolve("m2"); diff --git a/langtools/test/tools/javac/modules/DuplicateClassTest.java b/langtools/test/tools/javac/modules/DuplicateClassTest.java index 192def351e3..48e8332cd4c 100644 --- a/langtools/test/tools/javac/modules/DuplicateClassTest.java +++ b/langtools/test/tools/javac/modules/DuplicateClassTest.java @@ -47,7 +47,7 @@ public class DuplicateClassTest extends ModuleTestBase { } @Test - void testSimple(Path base) throws Exception { + public void testSimple(Path base) throws Exception { Path m1 = base.resolve("m1"); Path m2 = base.resolve("m2"); tb.writeJavaFiles(m1, diff --git a/langtools/test/tools/javac/modules/EdgeCases.java b/langtools/test/tools/javac/modules/EdgeCases.java index 4c80bd4f7b4..df3b9f65a9b 100644 --- a/langtools/test/tools/javac/modules/EdgeCases.java +++ b/langtools/test/tools/javac/modules/EdgeCases.java @@ -66,7 +66,7 @@ public class EdgeCases extends ModuleTestBase { } @Test - void testAddExportUndefinedModule(Path base) throws Exception { + public void testAddExportUndefinedModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "package test; import undef.Any; public class Test {}"); Path classes = base.resolve("classes"); @@ -89,7 +89,7 @@ public class EdgeCases extends ModuleTestBase { } @Test - void testModuleSymbolOutterMostClass(Path base) throws Exception { + public void testModuleSymbolOutterMostClass(Path base) throws Exception { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { Path moduleSrc = base.resolve("module-src"); @@ -110,7 +110,7 @@ public class EdgeCases extends ModuleTestBase { } @Test - void testParseEnterAnalyze(Path base) throws Exception { + public void testParseEnterAnalyze(Path base) throws Exception { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { Path moduleSrc = base.resolve("module-src"); @@ -148,7 +148,7 @@ public class EdgeCases extends ModuleTestBase { } @Test - void testModuleImplicitModuleBoundaries(Path base) throws Exception { + public void testModuleImplicitModuleBoundaries(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeJavaFiles(src_m1, @@ -180,7 +180,7 @@ public class EdgeCases extends ModuleTestBase { } @Test - void testAssignClassToAutomaticModule(Path base) throws Exception { + public void testAssignClassToAutomaticModule(Path base) throws Exception { //check that if a ClassSymbol belongs to an automatic module, it is properly assigned and not //duplicated when being accessed through a classfile. Path automaticSrc = base.resolve("automaticSrc"); @@ -239,7 +239,7 @@ public class EdgeCases extends ModuleTestBase { } @Test - void testEmptyImplicitModuleInfo(Path base) throws Exception { + public void testEmptyImplicitModuleInfo(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); Files.createDirectories(src_m1); @@ -270,7 +270,7 @@ public class EdgeCases extends ModuleTestBase { } @Test - void testClassPackageClash(Path base) throws Exception { + public void testClassPackageClash(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeJavaFiles(src_m1, diff --git a/langtools/test/tools/javac/modules/GraphsTest.java b/langtools/test/tools/javac/modules/GraphsTest.java index a27da147f32..aadc180b808 100644 --- a/langtools/test/tools/javac/modules/GraphsTest.java +++ b/langtools/test/tools/javac/modules/GraphsTest.java @@ -28,7 +28,8 @@ * @modules * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main - * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask ModuleTestBase + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.ModuleBuilder + * ModuleTestBase * @run main GraphsTest */ @@ -41,6 +42,7 @@ import java.util.regex.Pattern; import toolbox.JarTask; import toolbox.JavacTask; +import toolbox.ModuleBuilder; import toolbox.Task; import toolbox.ToolBox; @@ -69,11 +71,11 @@ public class GraphsTest extends ModuleTestBase { * */ @Test - void diamond(Path base) throws Exception { + public void diamond(Path base) throws Exception { Path modules = Files.createDirectories(base.resolve("modules")); - new ModuleBuilder("J") + new ModuleBuilder(tb, "J") .exports("openJ") .classes("package openJ; public class J { }") .classes("package closedJ; public class J { }") @@ -87,25 +89,25 @@ public class GraphsTest extends ModuleTestBase { .run() .writeAll(); - new ModuleBuilder("O") + new ModuleBuilder(tb, "O") .exports("openO") .requiresPublic("J", jarModules) .classes("package openO; public class O { openJ.J j; }") .classes("package closedO; public class O { }") .build(modules); - new ModuleBuilder("N") + new ModuleBuilder(tb, "N") .requiresPublic("O", modules, jarModules) .exports("openN") .classes("package openN; public class N { }") .classes("package closedN; public class N { }") .build(modules); - new ModuleBuilder("L") + new ModuleBuilder(tb, "L") .requiresPublic("O", modules, jarModules) .exports("openL") .classes("package openL; public class L { }") .classes("package closedL; public class L { }") .build(modules); - ModuleBuilder m = new ModuleBuilder("M"); + ModuleBuilder m = new ModuleBuilder(tb, "M"); //positive case Path positiveSrc = m .requires("N", modules) @@ -178,14 +180,14 @@ public class GraphsTest extends ModuleTestBase { @Test public void reexportOfQualifiedExport(Path base) throws Exception { Path modules = base.resolve("modules"); - new ModuleBuilder("M") + new ModuleBuilder(tb, "M") .requiresPublic("N") .write(modules); - new ModuleBuilder("N") + new ModuleBuilder(tb, "N") .exportsTo("pack", "M") .classes("package pack; public class Clazz { }") .write(modules); - new ModuleBuilder("L") + new ModuleBuilder(tb, "L") .requires("M") .classes("package p; public class A { A(pack.Clazz cl){} } ") .write(modules); diff --git a/langtools/test/tools/javac/modules/HelloWorldTest.java b/langtools/test/tools/javac/modules/HelloWorldTest.java index f0757ec167a..6240e306b14 100644 --- a/langtools/test/tools/javac/modules/HelloWorldTest.java +++ b/langtools/test/tools/javac/modules/HelloWorldTest.java @@ -58,7 +58,7 @@ public class HelloWorldTest extends ModuleTestBase { + HELLO_WORLD; @Test - void testLegacyMode(Path base) throws Exception { + public void testLegacyMode(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, HELLO_WORLD); @@ -85,7 +85,7 @@ public class HelloWorldTest extends ModuleTestBase { } @Test - void testUnnamedModule(Path base) throws Exception { + public void testUnnamedModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, HELLO_WORLD); @@ -101,7 +101,7 @@ public class HelloWorldTest extends ModuleTestBase { } @Test - void testSingleModule(Path base) throws Exception { + public void testSingleModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeFile(src.resolve("module-info.java"), "module m { }"); tb.writeJavaFiles(src, PKG_HELLO_WORLD); @@ -121,7 +121,7 @@ public class HelloWorldTest extends ModuleTestBase { } @Test - void testModuleSourcePath(Path base) throws Exception { + public void testModuleSourcePath(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }"); diff --git a/langtools/test/tools/javac/modules/MOptionTest.java b/langtools/test/tools/javac/modules/MOptionTest.java index cb265d867d4..cea2670f7c8 100644 --- a/langtools/test/tools/javac/modules/MOptionTest.java +++ b/langtools/test/tools/javac/modules/MOptionTest.java @@ -47,7 +47,7 @@ public class MOptionTest extends ModuleTestBase { } @Test - void testOneModule(Path base) throws Exception { + public void testOneModule(Path base) throws Exception { Path src = base.resolve("src"); Path m1 = src.resolve("m1"); Path build = base.resolve("build"); @@ -112,7 +112,7 @@ public class MOptionTest extends ModuleTestBase { } @Test - void testNoOutputDir(Path base) throws Exception { + public void testNoOutputDir(Path base) throws Exception { Path src = base.resolve("src"); Path m1 = src.resolve("m1"); Path build = base.resolve("build"); @@ -135,7 +135,7 @@ public class MOptionTest extends ModuleTestBase { } @Test - void testNoModuleSourcePath(Path base) throws Exception { + public void testNoModuleSourcePath(Path base) throws Exception { Path src = base.resolve("src"); Path m1 = src.resolve("m1"); Path build = base.resolve("build"); @@ -158,7 +158,7 @@ public class MOptionTest extends ModuleTestBase { } @Test - void testMultiModule(Path base) throws Exception { + public void testMultiModule(Path base) throws Exception { Path src = base.resolve("src"); Path m1 = src.resolve("m1"); Path m2 = src.resolve("m2"); diff --git a/langtools/test/tools/javac/modules/ModuleFinderTest.java b/langtools/test/tools/javac/modules/ModuleFinderTest.java index d1186b1ae5f..ed228469f85 100644 --- a/langtools/test/tools/javac/modules/ModuleFinderTest.java +++ b/langtools/test/tools/javac/modules/ModuleFinderTest.java @@ -48,7 +48,7 @@ public class ModuleFinderTest extends ModuleTestBase { } @Test - void testDuplicateModulesOnPath(Path base) throws Exception { + public void testDuplicateModulesOnPath(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m1 { }"); diff --git a/langtools/test/tools/javac/modules/ModuleInfoTest.java b/langtools/test/tools/javac/modules/ModuleInfoTest.java index 9b0e7c491a3..600afb321c7 100644 --- a/langtools/test/tools/javac/modules/ModuleInfoTest.java +++ b/langtools/test/tools/javac/modules/ModuleInfoTest.java @@ -51,7 +51,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Check error message if module declaration not in module-info.java. */ @Test - void testModuleDeclNotInModuleJava(Path base) throws Exception { + public void testModuleDeclNotInModuleJava(Path base) throws Exception { Path src = base.resolve("src"); tb.writeFile(src.resolve("M.java"), "module M { }"); String log = new JavacTask(tb) @@ -69,7 +69,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that a package private class can be put in module-info.java. */ @Test - void testNotModuleDeclInModuleJava_1(Path base) throws Exception { + public void testNotModuleDeclInModuleJava_1(Path base) throws Exception { Path src = base.resolve("src"); tb.writeFile(src.resolve("module-info.java"), "class C { }"); new JavacTask(tb) @@ -83,7 +83,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that a public class cannot be put in module-info.java. */ @Test - void testNotModuleDeclInModuleJava_2(Path base) throws Exception { + public void testNotModuleDeclInModuleJava_2(Path base) throws Exception { Path src = base.resolve("src"); tb.writeFile(src.resolve("module-info.java"), "public class C { }"); String log = new JavacTask(tb) @@ -101,7 +101,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that only one module decl can be put in module-info.java. */ @Test - void testSingleModuleDecl(Path base) throws Exception { + public void testSingleModuleDecl(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module M1 { } /*...*/ module M2 { }"); String log = new JavacTask(tb) @@ -119,7 +119,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that missing requires are reported. */ @Test - void testRequiresNotFound(Path base) throws Exception { + public void testRequiresNotFound(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module M1 { requires M2; }"); String log = new JavacTask(tb) @@ -137,7 +137,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that missing exports are reported. */ @Test - void testExportsNotFound(Path base) throws Exception { + public void testExportsNotFound(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module M1 { exports p to M2; }"); String log = new JavacTask(tb) @@ -155,7 +155,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that a simple loop is detected. */ @Test - void testRequiresSelf(Path base) throws Exception { + public void testRequiresSelf(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module M { requires M; }"); String log = new JavacTask(tb) @@ -173,7 +173,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that a multi-module loop is detected. */ @Test - void testRequiresLoop(Path base) throws Exception { + public void testRequiresLoop(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { requires m2; }"); @@ -201,7 +201,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that a multi-module loop is detected. */ @Test - void testRequiresPublicLoop(Path base) throws Exception { + public void testRequiresPublicLoop(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { requires m2; }"); @@ -229,7 +229,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that duplicate requires are detected. */ @Test - void testDuplicateRequires(Path base) throws Exception { + public void testDuplicateRequires(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }"); @@ -255,7 +255,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that duplicate exported packages are detected. */ @Test - void testDuplicateExports_packages(Path base) throws Exception { + public void testDuplicateExports_packages(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m1 { exports p; exports p; }"); @@ -278,7 +278,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that duplicate exported packages are detected. */ @Test - void testDuplicateExports_packages2(Path base) throws Exception { + public void testDuplicateExports_packages2(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p; exports p to m2; }"); tb.writeJavaFiles(src.resolve("m2"), "module m2 { }"); @@ -302,7 +302,7 @@ public class ModuleInfoTest extends ModuleTestBase { * Verify that duplicate exported packages are detected. */ @Test - void testDuplicateExports_modules(Path base) throws Exception { + public void testDuplicateExports_modules(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }"); diff --git a/langtools/test/tools/javac/modules/ModuleInfoTreeAccess.java b/langtools/test/tools/javac/modules/ModuleInfoTreeAccess.java index 3666875a4de..7e0917c9f81 100644 --- a/langtools/test/tools/javac/modules/ModuleInfoTreeAccess.java +++ b/langtools/test/tools/javac/modules/ModuleInfoTreeAccess.java @@ -61,7 +61,7 @@ public class ModuleInfoTreeAccess extends ModuleTestBase { } @Test - void testTreePathForModuleDecl(Path base) throws Exception { + public void testTreePathForModuleDecl(Path base) throws Exception { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { diff --git a/langtools/test/tools/javac/modules/ModulePathTest.java b/langtools/test/tools/javac/modules/ModulePathTest.java index d885512e632..9fb639841b7 100644 --- a/langtools/test/tools/javac/modules/ModulePathTest.java +++ b/langtools/test/tools/javac/modules/ModulePathTest.java @@ -30,7 +30,8 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap * jdk.jlink/jdk.tools.jmod - * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask ModuleTestBase + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.ModuleBuilder + * ModuleTestBase * @run main ModulePathTest */ @@ -41,6 +42,7 @@ import java.nio.file.Path; import toolbox.JarTask; import toolbox.JavacTask; +import toolbox.ModuleBuilder; import toolbox.Task; import toolbox.ToolBox; @@ -54,7 +56,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testNotExistsOnPath(Path base) throws Exception { + public void testNotExistsOnPath(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "class C { }"); @@ -71,7 +73,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testNotADirOnPath_1(Path base) throws Exception { + public void testNotADirOnPath_1(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "class C { }"); tb.writeFile("dummy.txt", ""); @@ -89,7 +91,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testNotADirOnPath_2(Path base) throws Exception { + public void testNotADirOnPath_2(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "class C { }"); tb.writeFile("dummy.jimage", ""); @@ -107,7 +109,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testExplodedModuleOnPath(Path base) throws Exception { + public void testExplodedModuleOnPath(Path base) throws Exception { Path modSrc = base.resolve("modSrc"); tb.writeJavaFiles(modSrc, "module m1 { exports p; }", @@ -137,7 +139,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testBadExplodedModuleOnPath(Path base) throws Exception { + public void testBadExplodedModuleOnPath(Path base) throws Exception { Path modClasses = base.resolve("modClasses"); tb.writeFile(modClasses.resolve("module-info.class"), "module m1 { }"); @@ -162,7 +164,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testAutoJarOnPath(Path base) throws Exception { + public void testAutoJarOnPath(Path base) throws Exception { Path jarSrc = base.resolve("jarSrc"); tb.writeJavaFiles(jarSrc, "package p; public class CC { }"); @@ -195,7 +197,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testModJarOnPath(Path base) throws Exception { + public void testModJarOnPath(Path base) throws Exception { Path jarSrc = base.resolve("jarSrc"); tb.writeJavaFiles(jarSrc, "module m1 { exports p; }", @@ -231,7 +233,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testBadJarOnPath(Path base) throws Exception { + public void testBadJarOnPath(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "class C { }"); tb.writeFile("dummy.jar", ""); @@ -249,7 +251,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testJModOnPath(Path base) throws Exception { + public void testJModOnPath(Path base) throws Exception { Path jmodSrc = base.resolve("jmodSrc"); tb.writeJavaFiles(jmodSrc, "module m1 { exports p; }", @@ -282,7 +284,7 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void testBadJModOnPath(Path base) throws Exception { + public void testBadJModOnPath(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "class C { }"); tb.writeFile("dummy.jmod", ""); @@ -300,9 +302,9 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void relativePath(Path base) throws Exception { + public void relativePath(Path base) throws Exception { final Path modules = base.resolve("modules"); - new ModuleBuilder("m1").build(modules); + new ModuleBuilder(tb, "m1").build(modules); Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m2 { requires m1; }", "class A { }"); @@ -316,9 +318,9 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void duplicatePaths_1(Path base) throws Exception { + public void duplicatePaths_1(Path base) throws Exception { final Path modules = base.resolve("modules"); - new ModuleBuilder("m1").build(modules); + new ModuleBuilder(tb, "m1").build(modules); Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m2 { requires m1; }", "class A { }"); @@ -332,9 +334,9 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void duplicatePaths_2(Path base) throws Exception { + public void duplicatePaths_2(Path base) throws Exception { final Path modules = base.resolve("modules"); - new ModuleBuilder("m1").build(modules); + new ModuleBuilder(tb, "m1").build(modules); Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m2 { requires m1; }", "class A { }"); @@ -349,15 +351,15 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void oneModuleHidesAnother(Path base) throws Exception { + public void oneModuleHidesAnother(Path base) throws Exception { final Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg1") .classes("package pkg1; public class E { }") .build(module); final Path deepModuleDir = module.resolve("deepModuleDir"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg2") .classes("package pkg2; public class E { }") .build(deepModuleDir); @@ -374,19 +376,19 @@ public class ModulePathTest extends ModuleTestBase { } @Test - void modulesInDifferentContainers(Path base) throws Exception { + public void modulesInDifferentContainers(Path base) throws Exception { final Path modules = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("one") .classes("package one; public class A { }") .build(modules); - new ModuleBuilder("m2") + new ModuleBuilder(tb, "m2") .requires("m1", modules) .build(base.resolve("tmp")); jar(base.resolve("tmp/m2"), modules.resolve("m2.jar")); - new ModuleBuilder("m3") + new ModuleBuilder(tb, "m3") .requires("m2", modules) .build(base.resolve("tmp")); jmod(base.resolve("tmp/m3"), modules.resolve("m3.jmod")); diff --git a/langtools/test/tools/javac/modules/ModuleSourcePathTest.java b/langtools/test/tools/javac/modules/ModuleSourcePathTest.java index dcb6b102592..e78a368e84d 100644 --- a/langtools/test/tools/javac/modules/ModuleSourcePathTest.java +++ b/langtools/test/tools/javac/modules/ModuleSourcePathTest.java @@ -56,7 +56,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void testSourcePathConflict(Path base) throws Exception { + public void testSourcePathConflict(Path base) throws Exception { Path sp = base.resolve("src"); Path msp = base.resolve("srcmodules"); @@ -74,7 +74,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void testUnnormalizedPath1(Path base) throws Exception { + public void testUnnormalizedPath1(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeJavaFiles(src_m1, "module m1 { }"); @@ -91,7 +91,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void testUnnormalizedPath2(Path base) throws Exception { + public void testUnnormalizedPath2(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeJavaFiles(src_m1, "module m1 { }"); @@ -115,7 +115,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void regularBraces(Path base) throws Exception { + public void regularBraces(Path base) throws Exception { generateModules(base, "src1", "src2/inner_dir"); final Path modules = base.resolve("modules"); @@ -136,7 +136,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void mismatchedBraces(Path base) throws Exception { + public void mismatchedBraces(Path base) throws Exception { final List sourcePaths = Arrays.asList( "{", "}", @@ -165,7 +165,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void deepBraces(Path base) throws Exception { + public void deepBraces(Path base) throws Exception { String[] modulePaths = {"src/src1", "src/src2", "src/src3", @@ -197,7 +197,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void fileInPath(Path base) throws Exception { + public void fileInPath(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("kettle$"), "module kettle$ { }", "package electric; class Heater { }"); tb.writeFile(base.resolve("dummy.txt"), ""); @@ -218,7 +218,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void noAlternative(Path base) throws Exception { + public void noAlternative(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("kettle$"), "module kettle$ { }", "package electric; class Heater { }"); @@ -238,7 +238,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void noChoice(Path base) throws Exception { + public void noChoice(Path base) throws Exception { tb.writeJavaFiles(base.resolve("kettle$"), "module kettle$ { }", "package electric; class Heater { }"); final Path modules = base.resolve("modules"); @@ -257,7 +257,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void nestedModules(Path src) throws Exception { + public void nestedModules(Path src) throws Exception { Path carModule = src.resolve("car"); tb.writeJavaFiles(carModule, "module car { }", "package light; class Headlight { }"); tb.writeJavaFiles(carModule.resolve("engine"), "module engine { }", "package flat; class Piston { }"); @@ -277,7 +277,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void relativePaths(Path base) throws Exception { + public void relativePaths(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("kettle"), "module kettle { }", "package electric; class Heater { }"); @@ -296,7 +296,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void duplicatePaths(Path base) throws Exception { + public void duplicatePaths(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { }", "package a; class A { }"); @@ -315,7 +315,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void notExistentPaths(Path base) throws Exception { + public void notExistentPaths(Path base) throws Exception { tb.writeJavaFiles(base.resolve("m1"), "module m1 { requires m0; }", "package a; class A { }"); final Path modules = base.resolve("modules"); @@ -334,7 +334,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void notExistentPathShouldBeSkipped(Path base) throws Exception { + public void notExistentPathShouldBeSkipped(Path base) throws Exception { tb.writeJavaFiles(base.resolve("m1"), "module m1 { }", "package a; class A { }"); final Path modules = base.resolve("modules"); @@ -352,7 +352,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void commas(Path base) throws Exception { + public void commas(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { }", "package a; class A { }"); @@ -371,7 +371,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void asterisk(Path base) throws Exception { + public void asterisk(Path base) throws Exception { tb.writeJavaFiles(base.resolve("kettle").resolve("classes"), "module kettle { }", "package electric; class Heater { }"); @@ -391,7 +391,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void asteriskInDifferentSets(Path base) throws Exception { + public void asteriskInDifferentSets(Path base) throws Exception { Path src = base.resolve("src"); final Path module = src.resolve("kettle"); tb.writeJavaFiles(module.resolve("classes"), "module kettle { }", "package electric; class Heater { }"); @@ -417,7 +417,7 @@ public class ModuleSourcePathTest extends ModuleTestBase { } @Test - void asteriskIllegalUse(Path base) throws Exception { + public void asteriskIllegalUse(Path base) throws Exception { final List sourcePaths = Arrays.asList( "*", "**", diff --git a/langtools/test/tools/javac/modules/ModuleTestBase.java b/langtools/test/tools/javac/modules/ModuleTestBase.java index 700e41417c4..d1dcfa9fb6a 100644 --- a/langtools/test/tools/javac/modules/ModuleTestBase.java +++ b/langtools/test/tools/javac/modules/ModuleTestBase.java @@ -43,19 +43,20 @@ import java.util.TreeSet; import java.util.stream.Collectors; import toolbox.JavacTask; +import toolbox.TestRunner; import toolbox.ToolBox; /** * Base class for module tests. */ -public class ModuleTestBase { +public class ModuleTestBase extends TestRunner { protected ToolBox tb; - protected PrintStream out; private int errors; - /** Marker annotation for test methods to be invoked by runTests. */ - @Retention(RetentionPolicy.RUNTIME) - @interface Test { } + ModuleTestBase() { + super(System.err); + tb = new ToolBox(); + } /** * Run all methods annotated with @Test, and throw an exception if any @@ -63,47 +64,12 @@ public class ModuleTestBase { * * @throws Exception if any errors occurred */ - void runTests() throws Exception { - if (tb == null) - tb = new ToolBox(); - out = System.err; - - for (Method m: getClass().getDeclaredMethods()) { - Annotation a = m.getAnnotation(Test.class); - if (a != null) { - try { - out.println("Running test " + m.getName()); - Path baseDir = Paths.get(m.getName()); - m.invoke(this, new Object[] { baseDir }); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - error("Exception: " + e.getCause()); - cause.printStackTrace(out); - } - out.println(); - } - } - if (errors > 0) - throw new Exception(errors + " errors occurred"); + protected void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); } - // move to ToolBox? - // change returntyp to List -- means updating ToolBox methods Path[] findJavaFiles(Path... paths) throws IOException { - Set files = new TreeSet<>(); - for (Path p : paths) { - Files.walkFileTree(p, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - if (file.getFileName().toString().endsWith(".java")) { - files.add(file); - } - return FileVisitResult.CONTINUE; - } - }); - } - return files.toArray(new Path[files.size()]); + return tb.findJavaFiles(paths); } void error(String message) { @@ -111,79 +77,4 @@ public class ModuleTestBase { errors++; } - public class ModuleBuilder { - - private final String name; - private String requires = ""; - private String exports = ""; - private String uses = ""; - private String provides = ""; - private String modulePath = ""; - private List content = new ArrayList<>(); - - public ModuleBuilder(String name) { - this.name = name; - } - - public ModuleBuilder requiresPublic(String requires, Path... modulePath) { - return requires("public " + requires, modulePath); - } - - public ModuleBuilder requires(String requires, Path... modulePath) { - this.requires += " requires " + requires + ";\n"; - this.modulePath += Arrays.stream(modulePath) - .map(Path::toString) - .collect(Collectors.joining(File.pathSeparator)); - return this; - } - - public ModuleBuilder exportsTo(String pkg, String module) { - return exports(pkg + " to " + module); - } - - public ModuleBuilder exports(String pkg) { - this.exports += " exports " + pkg + ";\n"; - return this; - } - - public ModuleBuilder uses(String uses) { - this.uses += " uses " + uses + ";\n"; - return this; - } - - public ModuleBuilder provides(String service, String implementation) { - this.provides += " provides " + service + " with " + implementation + ";\n"; - return this; - } - - public ModuleBuilder classes(String... content) { - this.content.addAll(Arrays.asList(content)); - return this; - } - - public Path write(Path where) throws IOException { - Files.createDirectories(where); - List sources = new ArrayList<>(); - sources.add("module " + name + "{" - + requires - + exports - + uses - + provides - + "}"); - sources.addAll(content); - Path moduleSrc = where.resolve(name + "/src"); - tb.writeJavaFiles(moduleSrc, sources.toArray(new String[]{})); - return moduleSrc; - } - - public void build(Path where) throws IOException { - Path moduleSrc = write(where); - new JavacTask(tb) - .outdir(where.resolve(name)) - .options("-mp", modulePath) - .files(findJavaFiles(moduleSrc)) - .run() - .writeAll(); - } - } } diff --git a/langtools/test/tools/javac/modules/ModulesAndClassPathTest.java b/langtools/test/tools/javac/modules/ModulesAndClassPathTest.java index 01c75bd3462..ce727c422a2 100644 --- a/langtools/test/tools/javac/modules/ModulesAndClassPathTest.java +++ b/langtools/test/tools/javac/modules/ModulesAndClassPathTest.java @@ -55,7 +55,7 @@ public class ModulesAndClassPathTest extends ModuleTestBase { } @Test - void testModulesAndClassPath(Path base) throws Exception { + public void testModulesAndClassPath(Path base) throws Exception { Path jar = prepareTestJar(base); Path moduleSrc = base.resolve("module-src"); @@ -106,7 +106,7 @@ public class ModulesAndClassPathTest extends ModuleTestBase { } @Test - void testImplicitSourcePathModuleInfo(Path base) throws Exception { + public void testImplicitSourcePathModuleInfo(Path base) throws Exception { Path jar = prepareTestJar(base); Path moduleSrc = base.resolve("module-src"); @@ -139,7 +139,7 @@ public class ModulesAndClassPathTest extends ModuleTestBase { } @Test - void testModuleInfoFromOutput(Path base) throws Exception { + public void testModuleInfoFromOutput(Path base) throws Exception { Path jar = prepareTestJar(base); Path moduleSrc = base.resolve("module-src"); @@ -221,7 +221,7 @@ public class ModulesAndClassPathTest extends ModuleTestBase { } @Test - void testClassOutputVisibleForIncrementalCompilation(Path base) throws Exception { + public void testClassOutputVisibleForIncrementalCompilation(Path base) throws Exception { Path moduleSrc = base.resolve("module-src"); Path m1 = moduleSrc.resolve("m1"); diff --git a/langtools/test/tools/javac/modules/MultiModuleModeTest.java b/langtools/test/tools/javac/modules/MultiModuleModeTest.java index f7291988c6b..e72995bf5ac 100644 --- a/langtools/test/tools/javac/modules/MultiModuleModeTest.java +++ b/langtools/test/tools/javac/modules/MultiModuleModeTest.java @@ -49,7 +49,7 @@ public class MultiModuleModeTest extends ModuleTestBase { } @Test - void testDuplicateModules(Path base) throws Exception { + public void testDuplicateModules(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeJavaFiles(src_m1, "module m1 { }"); @@ -72,7 +72,7 @@ public class MultiModuleModeTest extends ModuleTestBase { } @Test - void testCantFindModule(Path base) throws Exception { + public void testCantFindModule(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeJavaFiles(src_m1, "module m1 { }"); @@ -95,7 +95,7 @@ public class MultiModuleModeTest extends ModuleTestBase { } @Test - void testModuleNameMismatch(Path base) throws Exception { + public void testModuleNameMismatch(Path base) throws Exception { Path src = base.resolve("src"); Path src_m1 = src.resolve("m1"); tb.writeJavaFiles(src_m1, "module m2 { }"); @@ -116,7 +116,7 @@ public class MultiModuleModeTest extends ModuleTestBase { } @Test - void testImplicitModuleSource(Path base) throws Exception { + public void testImplicitModuleSource(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { }"); tb.writeJavaFiles(src.resolve("m2"), "module m2 { requires m1; }"); @@ -132,7 +132,7 @@ public class MultiModuleModeTest extends ModuleTestBase { } @Test - void testImplicitModuleClass(Path base) throws Exception { + public void testImplicitModuleClass(Path base) throws Exception { Path src1 = base.resolve("src1"); tb.writeJavaFiles(src1.resolve("m1"), "module m1 { }"); Path modules1 = base.resolve("modules1"); diff --git a/langtools/test/tools/javac/modules/NPECompilingModuleInfoTest.java b/langtools/test/tools/javac/modules/NPECompilingModuleInfoTest.java index e1ca690294f..ec70ec2c96b 100644 --- a/langtools/test/tools/javac/modules/NPECompilingModuleInfoTest.java +++ b/langtools/test/tools/javac/modules/NPECompilingModuleInfoTest.java @@ -45,7 +45,7 @@ public class NPECompilingModuleInfoTest extends ModuleTestBase { } @Test - void testCompileNoError(Path base) throws Exception { + public void testCompileNoError(Path base) throws Exception { Path mod = base.resolve("mod"); tb.writeJavaFiles(mod, "module mod { exports pkg; }"); Path pkg = mod.resolve("pkg"); diff --git a/langtools/test/tools/javac/modules/NPEEmptyFileTest.java b/langtools/test/tools/javac/modules/NPEEmptyFileTest.java index 4b44e996961..3ace4bb0326 100644 --- a/langtools/test/tools/javac/modules/NPEEmptyFileTest.java +++ b/langtools/test/tools/javac/modules/NPEEmptyFileTest.java @@ -45,7 +45,7 @@ public class NPEEmptyFileTest extends ModuleTestBase { } @Test - void compileEmptyFile(Path base) throws Exception { + public void compileEmptyFile(Path base) throws Exception { Path modules = base.resolve("modules"); Files.createDirectories(modules); Path emptyJavaFile = base.resolve("Test.java"); diff --git a/langtools/test/tools/javac/modules/OutputDirTest.java b/langtools/test/tools/javac/modules/OutputDirTest.java index 6e4d5d0573d..0236a7bda6a 100644 --- a/langtools/test/tools/javac/modules/OutputDirTest.java +++ b/langtools/test/tools/javac/modules/OutputDirTest.java @@ -60,7 +60,7 @@ public class OutputDirTest extends ModuleTestBase { } @Test - void testError(Path base) throws Exception { + public void testError(Path base) throws Exception { String log = new JavacTask(tb) .options("-XDrawDiagnostics", "-modulesourcepath", src.toString()) @@ -74,7 +74,7 @@ public class OutputDirTest extends ModuleTestBase { } @Test - void testProcOnly(Path base) throws IOException { + public void testProcOnly(Path base) throws IOException { new JavacTask(tb) .options("-XDrawDiagnostics", "-proc:only", @@ -85,7 +85,7 @@ public class OutputDirTest extends ModuleTestBase { } @Test - void testClassOutDir(Path base) throws IOException { + public void testClassOutDir(Path base) throws IOException { Path classes = base.resolve("classes"); new JavacTask(tb) .options("-XDrawDiagnostics", @@ -97,7 +97,7 @@ public class OutputDirTest extends ModuleTestBase { } @Test - void testExplodedOutDir(Path base) throws Exception { + public void testExplodedOutDir(Path base) throws Exception { Path modSrc = base.resolve("modSrc"); tb.writeJavaFiles(modSrc, "module m1 { exports p; }", @@ -131,7 +131,7 @@ public class OutputDirTest extends ModuleTestBase { } @Test - void testInExplodedOutDir(Path base) throws Exception { + public void testInExplodedOutDir(Path base) throws Exception { Path modSrc = base.resolve("modSrc"); tb.writeJavaFiles(modSrc, "module m1 { exports p; }", diff --git a/langtools/test/tools/javac/modules/PackageConflictTest.java b/langtools/test/tools/javac/modules/PackageConflictTest.java index 7ebe29927fc..c091089f77a 100644 --- a/langtools/test/tools/javac/modules/PackageConflictTest.java +++ b/langtools/test/tools/javac/modules/PackageConflictTest.java @@ -28,7 +28,7 @@ * @modules * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main - * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase + * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase * @run main PackageConflictTest */ @@ -38,6 +38,7 @@ import java.util.Arrays; import java.util.List; import toolbox.JavacTask; +import toolbox.ModuleBuilder; import toolbox.Task; import toolbox.ToolBox; @@ -48,7 +49,7 @@ public class PackageConflictTest extends ModuleTestBase { } @Test - void testSimple(Path base) throws Exception { + public void testSimple(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "package java.util; public class MyList { }"); @@ -68,7 +69,7 @@ public class PackageConflictTest extends ModuleTestBase { } @Test - void testDisjoint(Path base) throws Exception { + public void testDisjoint(Path base) throws Exception { Path m1 = base.resolve("m1"); Path m2 = base.resolve("m2"); tb.writeJavaFiles(m1, @@ -89,7 +90,7 @@ public class PackageConflictTest extends ModuleTestBase { } @Test - void testConflictInDependencies(Path base) throws Exception { + public void testConflictInDependencies(Path base) throws Exception { Path m1 = base.resolve("m1"); Path m2 = base.resolve("m2"); Path m3 = base.resolve("m3"); @@ -123,13 +124,13 @@ public class PackageConflictTest extends ModuleTestBase { } @Test - void testSimple2(Path base) throws Exception { + public void testSimple2(Path base) throws Exception { Path modules = base.resolve("modules"); - new ModuleBuilder("N") + new ModuleBuilder(tb, "N") .exports("pack") .classes("package pack; public class A { }") .build(modules); - new ModuleBuilder("M") + new ModuleBuilder(tb, "M") .requires("N") .classes("package pack; public class B { pack.A f; }") .write(modules); @@ -147,14 +148,14 @@ public class PackageConflictTest extends ModuleTestBase { } @Test - void testPrivateConflict(Path base) throws Exception { + public void testPrivateConflict(Path base) throws Exception { Path modules = base.resolve("modules"); - new ModuleBuilder("N") + new ModuleBuilder(tb, "N") .exports("publ") .classes("package pack; public class A { }") .classes("package publ; public class B { }") .write(modules); - new ModuleBuilder("M") + new ModuleBuilder(tb, "M") .requires("N") .classes("package pack; public class C { publ.B b; }") .write(modules); @@ -173,14 +174,14 @@ public class PackageConflictTest extends ModuleTestBase { } @Test - void testPrivateConflictOnModulePath(Path base) throws Exception { + public void testPrivateConflictOnModulePath(Path base) throws Exception { Path modules = base.resolve("modules"); - new ModuleBuilder("N") + new ModuleBuilder(tb, "N") .exports("publ") .classes("package pack; public class A { }") .classes("package publ; public class B { }") .build(modules); - new ModuleBuilder("M") + new ModuleBuilder(tb, "M") .requires("N") .classes("package pack; public class C { publ.B b; }") .write(modules); @@ -199,17 +200,17 @@ public class PackageConflictTest extends ModuleTestBase { } @Test - void testRequiresConflictExports(Path base) throws Exception { + public void testRequiresConflictExports(Path base) throws Exception { Path modules = base.resolve("modules"); - new ModuleBuilder("M") + new ModuleBuilder(tb, "M") .exports("pack") .classes("package pack; public class A { }") .build(modules); - new ModuleBuilder("N") + new ModuleBuilder(tb, "N") .exports("pack") .classes("package pack; public class B { }") .build(modules); - new ModuleBuilder("K") + new ModuleBuilder(tb, "K") .requires("M") .requires("N") .classes("package pkg; public class C { pack.A a; pack.B b; }") @@ -231,18 +232,18 @@ public class PackageConflictTest extends ModuleTestBase { } @Test - void testQulifiedExportsToDifferentModules(Path base) throws Exception { + public void testQulifiedExportsToDifferentModules(Path base) throws Exception { Path modules = base.resolve("modules"); - new ModuleBuilder("U").write(modules); - new ModuleBuilder("M") + new ModuleBuilder(tb, "U").write(modules); + new ModuleBuilder(tb, "M") .exports("pkg to U") .classes("package pkg; public class A { public static boolean flagM; }") .write(modules); - new ModuleBuilder("N") + new ModuleBuilder(tb, "N") .exports("pkg to K") .classes("package pkg; public class A { public static boolean flagN; }") .write(modules); - ModuleBuilder moduleK = new ModuleBuilder("K"); + ModuleBuilder moduleK = new ModuleBuilder(tb, "K"); moduleK.requires("M") .requires("N") .classes("package p; public class DependsOnN { boolean f = pkg.A.flagN; } ") diff --git a/langtools/test/tools/javac/modules/PackageMultipleModules.java b/langtools/test/tools/javac/modules/PackageMultipleModules.java index 8f2ae2de90f..888fdaa72e9 100644 --- a/langtools/test/tools/javac/modules/PackageMultipleModules.java +++ b/langtools/test/tools/javac/modules/PackageMultipleModules.java @@ -49,7 +49,7 @@ public class PackageMultipleModules extends ModuleTestBase { } @Test - void testSimple(Path base) throws Exception { + public void testSimple(Path base) throws Exception { Path m1 = base.resolve("m1"); Path m2 = base.resolve("m2"); tb.writeJavaFiles(m1, diff --git a/langtools/test/tools/javac/modules/PluginsInModulesTest.java b/langtools/test/tools/javac/modules/PluginsInModulesTest.java index aea94a63729..480b147a7a2 100644 --- a/langtools/test/tools/javac/modules/PluginsInModulesTest.java +++ b/langtools/test/tools/javac/modules/PluginsInModulesTest.java @@ -127,7 +127,7 @@ public class PluginsInModulesTest extends ModuleTestBase { Path classes; @Test - void testUseOnlyOneProcessor(Path base) throws Exception { + public void testUseOnlyOneProcessor(Path base) throws Exception { initialization(base); List log = new JavacTask(tb) .options("-processormodulepath", processorCompiledModules.toString(), diff --git a/langtools/test/tools/javac/modules/ProvidesTest.java b/langtools/test/tools/javac/modules/ProvidesTest.java index 63c3f56a4e0..2224e26fc63 100644 --- a/langtools/test/tools/javac/modules/ProvidesTest.java +++ b/langtools/test/tools/javac/modules/ProvidesTest.java @@ -48,7 +48,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testSimple(Path base) throws Exception { + public void testSimple(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.C1 with p2.C2; }", @@ -65,7 +65,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testMulti(Path base) throws Exception { + public void testMulti(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p1; }", @@ -86,7 +86,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testMissingWith(Path base) throws Exception { + public void testMissingWith(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p.C; }", @@ -108,7 +108,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testDuplicateProvides(Path base) throws Exception { + public void testDuplicateProvides(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.C1 with p2.C2; provides p1.C1 with p2.C2; }", @@ -126,7 +126,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testMissingService(Path base) throws Exception { + public void testMissingService(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p.Missing with p.C; }", @@ -151,7 +151,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testProvidesFromAnotherModule(Path base) throws Exception { + public void testProvidesFromAnotherModule(Path base) throws Exception { Path modules = base.resolve("modules"); tb.writeJavaFiles(modules.resolve("M"), "module M { exports p; }", @@ -177,7 +177,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testServiceIsNotImplemented(Path base) throws Exception { + public void testServiceIsNotImplemented(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p.A with p.B; }", @@ -200,7 +200,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testMissingImplementation(Path base) throws Exception { + public void testMissingImplementation(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p.C with p.Impl; }", @@ -222,7 +222,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testSeveralImplementations(Path base) throws Exception { + public void testSeveralImplementations(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p.C with p.Impl1; provides p.C with p.Impl2; }", @@ -238,7 +238,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testOneImplementationsForServices(Path base) throws Exception { + public void testOneImplementationsForServices(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p.Service1 with p.Impl; provides p.Service2 with p.Impl; }", @@ -254,7 +254,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testAbstractImplementation(Path base) throws Exception { + public void testAbstractImplementation(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.C1 with p2.C2; }", @@ -277,7 +277,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testInterfaceImplementation(Path base) throws Exception { + public void testInterfaceImplementation(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.Service with p2.Impl; }", @@ -300,7 +300,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testProtectedImplementation(Path base) throws Exception { + public void testProtectedImplementation(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.C1 with p2.C2; }", @@ -323,7 +323,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testNoNoArgConstructor(Path base) throws Exception { + public void testNoNoArgConstructor(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses p1.C1; provides p1.C1 with p2.C2; }", @@ -346,7 +346,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testPrivateNoArgConstructor(Path base) throws Exception { + public void testPrivateNoArgConstructor(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses p1.C1; provides p1.C1 with p2.C2; }", @@ -369,7 +369,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testServiceIndirectlyImplemented(Path base) throws Exception { + public void testServiceIndirectlyImplemented(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.C1 with p2.C3; }", @@ -385,7 +385,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testServiceImplementationInnerClass(Path base) throws Exception { + public void testServiceImplementationInnerClass(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.C1 with p2.C2.Inner; }", @@ -408,7 +408,7 @@ public class ProvidesTest extends ModuleTestBase { } @Test - void testServiceDefinitionInnerClass(Path base) throws Exception { + public void testServiceDefinitionInnerClass(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.C1.InnerDefinition with p2.C2; }", diff --git a/langtools/test/tools/javac/modules/QueryBeforeEnter.java b/langtools/test/tools/javac/modules/QueryBeforeEnter.java index 4e606fe48df..669d95f03ec 100644 --- a/langtools/test/tools/javac/modules/QueryBeforeEnter.java +++ b/langtools/test/tools/javac/modules/QueryBeforeEnter.java @@ -65,7 +65,7 @@ public class QueryBeforeEnter extends ModuleTestBase { } @Test - void testEmpty(Path base) throws Exception { + public void testEmpty(Path base) throws Exception { JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); com.sun.source.util.JavacTask task = (com.sun.source.util.JavacTask) javaCompiler.getTask(null, null, null, null, null, null); @@ -75,7 +75,7 @@ public class QueryBeforeEnter extends ModuleTestBase { } @Test - void testUnnamed(Path base) throws Exception { + public void testUnnamed(Path base) throws Exception { Path moduleSrc = base.resolve("module-src"); Path m1 = moduleSrc.resolve("m1"); @@ -151,7 +151,7 @@ public class QueryBeforeEnter extends ModuleTestBase { } @Test - void testSingleNamed(Path base) throws Exception { + public void testSingleNamed(Path base) throws Exception { Path moduleSrc = base.resolve("module-src"); Path m1 = moduleSrc.resolve("m1"); @@ -226,7 +226,7 @@ public class QueryBeforeEnter extends ModuleTestBase { } @Test - void testMultiModule(Path base) throws Exception { + public void testMultiModule(Path base) throws Exception { Path modulePathSrc = base.resolve("module-path-src"); Path m1 = modulePathSrc.resolve("m1"); @@ -311,7 +311,7 @@ public class QueryBeforeEnter extends ModuleTestBase { } @Test - void testTooSoon(Path base) throws Exception { + public void testTooSoon(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, diff --git a/langtools/test/tools/javac/modules/RepeatedUsesAndProvidesTest.java b/langtools/test/tools/javac/modules/RepeatedUsesAndProvidesTest.java index c5ea6903b9d..da1f5c8814e 100644 --- a/langtools/test/tools/javac/modules/RepeatedUsesAndProvidesTest.java +++ b/langtools/test/tools/javac/modules/RepeatedUsesAndProvidesTest.java @@ -46,7 +46,7 @@ public class RepeatedUsesAndProvidesTest extends ModuleTestBase { } @Test - void testDuplicateUses(Path base) throws Exception { + public void testDuplicateUses(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses p1.C1; uses p1.C1; }", @@ -66,7 +66,7 @@ public class RepeatedUsesAndProvidesTest extends ModuleTestBase { } @Test - void testDuplicateProvides(Path base) throws Exception { + public void testDuplicateProvides(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.C1 with p2.C2; provides p1.C1 with p2.C2; }", diff --git a/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java b/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java index 5fd54e9afcc..b36944b196c 100644 --- a/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java +++ b/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java @@ -46,7 +46,7 @@ public class ReportNonExistentPackageTest extends ModuleTestBase { } @Test - void testExportUnknownPackage(Path base) throws Exception { + public void testExportUnknownPackage(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { exports p1; }"); Path classes = base.resolve("classes"); @@ -64,7 +64,7 @@ public class ReportNonExistentPackageTest extends ModuleTestBase { } @Test - void testExportEmptyPackage(Path base) throws Exception { + public void testExportEmptyPackage(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { exports p1; }", @@ -84,7 +84,7 @@ public class ReportNonExistentPackageTest extends ModuleTestBase { } @Test - void testPackageWithMemberWOPackageDeclaration(Path base) throws Exception { + public void testPackageWithMemberWOPackageDeclaration(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { exports p1; }"); Path p1 = src.resolve("p1"); diff --git a/langtools/test/tools/javac/modules/RequiresPublicTest.java b/langtools/test/tools/javac/modules/RequiresPublicTest.java index 6b24ec871fa..7ce53d21fe3 100644 --- a/langtools/test/tools/javac/modules/RequiresPublicTest.java +++ b/langtools/test/tools/javac/modules/RequiresPublicTest.java @@ -47,7 +47,7 @@ public class RequiresPublicTest extends ModuleTestBase { } @Test - void testJavaSE_OK(Path base) throws Exception { + public void testJavaSE_OK(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { requires java.se; }", @@ -66,7 +66,7 @@ public class RequiresPublicTest extends ModuleTestBase { } @Test - void testJavaSE_Fail(Path base) throws Exception { + public void testJavaSE_Fail(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { requires java.se; }", @@ -90,7 +90,7 @@ public class RequiresPublicTest extends ModuleTestBase { } @Test - void testComplex_OK(Path base) throws Exception { + public void testComplex_OK(Path base) throws Exception { Path src = getComplexSrc(base, "", ""); Path classes = base.resolve("classes"); Files.createDirectories(classes); @@ -104,7 +104,7 @@ public class RequiresPublicTest extends ModuleTestBase { } @Test - void testComplex_Fail(Path base) throws Exception { + public void testComplex_Fail(Path base) throws Exception { Path src = getComplexSrc(base, "import p5.C5; import p6.C6; import p7.C7;\n", "C5 c5; C6 c6; C7 c7;\n"); diff --git a/langtools/test/tools/javac/modules/ResolveTest.java b/langtools/test/tools/javac/modules/ResolveTest.java index 958cf4e2888..6b4fc51d7bd 100644 --- a/langtools/test/tools/javac/modules/ResolveTest.java +++ b/langtools/test/tools/javac/modules/ResolveTest.java @@ -45,7 +45,7 @@ public class ResolveTest extends ModuleTestBase { } @Test - void testMissingSimpleTypeUnnamedModule(Path base) throws Exception { + public void testMissingSimpleTypeUnnamedModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "class C { D d; }"); @@ -62,7 +62,7 @@ public class ResolveTest extends ModuleTestBase { } @Test - void testMissingSimpleTypeNamedModule(Path base) throws Exception { + public void testMissingSimpleTypeNamedModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { }", @@ -81,7 +81,7 @@ public class ResolveTest extends ModuleTestBase { } @Test - void testUnexportedTypeUnreadableModule(Path base) throws Exception { + public void testUnexportedTypeUnreadableModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { }", @@ -105,7 +105,7 @@ public class ResolveTest extends ModuleTestBase { } @Test - void testUnexportedTypeReadableModule(Path base) throws Exception { + public void testUnexportedTypeReadableModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { }", @@ -129,7 +129,7 @@ public class ResolveTest extends ModuleTestBase { } @Test - void testQualifiedExportedTypeReadableModule(Path base) throws Exception { + public void testQualifiedExportedTypeReadableModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p1 to m3; }", @@ -155,7 +155,7 @@ public class ResolveTest extends ModuleTestBase { } @Test - void testExportedTypeUnreadableModule(Path base) throws Exception { + public void testExportedTypeUnreadableModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p1; }", @@ -179,7 +179,7 @@ public class ResolveTest extends ModuleTestBase { } @Test - void testExportedTypeReadableModule(Path base) throws Exception { + public void testExportedTypeReadableModule(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p1; }", @@ -199,7 +199,7 @@ public class ResolveTest extends ModuleTestBase { } @Test - void testExportedTypeReadableModule2(Path base) throws Exception { + public void testExportedTypeReadableModule2(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p1 to m2; }", diff --git a/langtools/test/tools/javac/modules/ServiceInStaticClassErrorTest.java b/langtools/test/tools/javac/modules/ServiceInStaticClassErrorTest.java index e05d12265d6..c242cd3efb4 100644 --- a/langtools/test/tools/javac/modules/ServiceInStaticClassErrorTest.java +++ b/langtools/test/tools/javac/modules/ServiceInStaticClassErrorTest.java @@ -48,7 +48,7 @@ public class ServiceInStaticClassErrorTest extends ModuleTestBase { } @Test - void testError(Path base) throws Exception { + public void testError(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.I with p1.Outer.A; }", diff --git a/langtools/test/tools/javac/modules/ServiceProvidedButNotExportedOrUsedTest.java b/langtools/test/tools/javac/modules/ServiceProvidedButNotExportedOrUsedTest.java index 062b39d2c5f..60899853871 100644 --- a/langtools/test/tools/javac/modules/ServiceProvidedButNotExportedOrUsedTest.java +++ b/langtools/test/tools/javac/modules/ServiceProvidedButNotExportedOrUsedTest.java @@ -49,7 +49,7 @@ public class ServiceProvidedButNotExportedOrUsedTest extends ModuleTestBase { } @Test - void testWarning(Path base) throws Exception { + public void testWarning(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { provides p1.C1 with p2.C2; }", @@ -76,7 +76,7 @@ public class ServiceProvidedButNotExportedOrUsedTest extends ModuleTestBase { } @Test - void testImplementationMustBeInSameModuleAsProvidesDirective(Path base) throws Exception { + public void testImplementationMustBeInSameModuleAsProvidesDirective(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p1; }", diff --git a/langtools/test/tools/javac/modules/SingleModuleModeTest.java b/langtools/test/tools/javac/modules/SingleModuleModeTest.java index 4b547723b9a..319c8c20f36 100644 --- a/langtools/test/tools/javac/modules/SingleModuleModeTest.java +++ b/langtools/test/tools/javac/modules/SingleModuleModeTest.java @@ -59,7 +59,7 @@ public class SingleModuleModeTest extends ModuleTestBase{ } @Test - void testTooManyModules(Path base) throws Exception { + public void testTooManyModules(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { }"); tb.writeJavaFiles(src.resolve("m2"), "module m2 { }"); @@ -76,7 +76,7 @@ public class SingleModuleModeTest extends ModuleTestBase{ } @Test - void testImplicitModuleSource(Path base) throws Exception { + public void testImplicitModuleSource(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { }", @@ -90,7 +90,7 @@ public class SingleModuleModeTest extends ModuleTestBase{ } @Test - void testImplicitModuleClass(Path base) throws Exception { + public void testImplicitModuleClass(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { }", @@ -112,7 +112,7 @@ public class SingleModuleModeTest extends ModuleTestBase{ } @Test - void testImplicitModuleClassAP(Path base) throws Exception { + public void testImplicitModuleClassAP(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses java.lang.Runnable; }", @@ -137,7 +137,7 @@ public class SingleModuleModeTest extends ModuleTestBase{ } @Test - void testImplicitModuleSourceAP(Path base) throws Exception { + public void testImplicitModuleSourceAP(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses java.lang.Runnable; }", diff --git a/langtools/test/tools/javac/modules/SubpackageTest.java b/langtools/test/tools/javac/modules/SubpackageTest.java index 034f3248b6e..87e9fc9fd46 100644 --- a/langtools/test/tools/javac/modules/SubpackageTest.java +++ b/langtools/test/tools/javac/modules/SubpackageTest.java @@ -52,7 +52,7 @@ public class SubpackageTest extends ModuleTestBase { } @Test // based on JDK-8075435 - void testUnnamedModule(Path base) throws Exception { + public void testUnnamedModule(Path base) throws Exception { Path libsrc = base.resolve("lib/src"); tb.writeJavaFiles(libsrc, "package p; public class E extends Error { }"); @@ -83,7 +83,7 @@ public class SubpackageTest extends ModuleTestBase { } @Test - void testSimpleMulti(Path base) throws Exception { + public void testSimpleMulti(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("mp"), "module mp { exports p; }", diff --git a/langtools/test/tools/javac/modules/UpgradeModulePathTest.java b/langtools/test/tools/javac/modules/UpgradeModulePathTest.java index 63c0741ae18..988076c0e9a 100644 --- a/langtools/test/tools/javac/modules/UpgradeModulePathTest.java +++ b/langtools/test/tools/javac/modules/UpgradeModulePathTest.java @@ -28,7 +28,7 @@ * @modules * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main - * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase + * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase * @run main UpgradeModulePathTest */ @@ -36,6 +36,7 @@ import java.io.File; import java.nio.file.Path; import toolbox.JavacTask; +import toolbox.ModuleBuilder; import toolbox.Task; import toolbox.ToolBox; @@ -47,15 +48,15 @@ public class UpgradeModulePathTest extends ModuleTestBase { } @Test - void simpleUsage(Path base) throws Exception { + public void simpleUsage(Path base) throws Exception { final Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg1") .classes("package pkg1; public class E { }") .build(module); final Path upgradeModule = base.resolve("upgradeModule"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg2") .classes("package pkg2; public class E { }") .build(upgradeModule); @@ -73,15 +74,15 @@ public class UpgradeModulePathTest extends ModuleTestBase { } @Test - void onlyUpgradeModulePath(Path base) throws Exception { + public void onlyUpgradeModulePath(Path base) throws Exception { final Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg1") .classes("package pkg1; public class E { }") .build(module); final Path upgradeModule = base.resolve("upgradeModule"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg2") .classes("package pkg2; public class E { }") .build(upgradeModule); @@ -98,15 +99,15 @@ public class UpgradeModulePathTest extends ModuleTestBase { } @Test - void withModuleSourcePath(Path base) throws Exception { + public void withModuleSourcePath(Path base) throws Exception { final Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg1") .classes("package pkg1; public class E { }") .build(module); final Path upgradeModule = base.resolve("upgradeModule"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg2") .classes("package pkg2; public class E { }") .build(upgradeModule); @@ -115,7 +116,7 @@ public class UpgradeModulePathTest extends ModuleTestBase { tb.writeJavaFiles(s.resolve("m3"), "module m3 { }"); final Path upgradeModule3 = base.resolve("upgradeModule"); - new ModuleBuilder("m3") + new ModuleBuilder(tb, "m3") .exports("pkg3") .classes("package pkg3; public class E { }") .build(upgradeModule); @@ -135,15 +136,15 @@ public class UpgradeModulePathTest extends ModuleTestBase { } @Test - void sameUpgradeAndModulePath(Path base) throws Exception { + public void sameUpgradeAndModulePath(Path base) throws Exception { final Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg1") .classes("package pkg1; public class E { }") .build(module); final Path upgradeModule = base.resolve("upgradeModule"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg2") .classes("package pkg2; public class E { }") .build(upgradeModule); @@ -161,9 +162,9 @@ public class UpgradeModulePathTest extends ModuleTestBase { } @Test - void dummyFileInUpgradeModulePath(Path base) throws Exception { + public void dummyFileInUpgradeModulePath(Path base) throws Exception { final Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg1") .classes("package pkg1; public class E { }") .build(module); @@ -189,24 +190,24 @@ public class UpgradeModulePathTest extends ModuleTestBase { } @Test - void severalUpgradeModules(Path base) throws Exception { + public void severalUpgradeModules(Path base) throws Exception { final Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg1") .classes("package pkg1; public class A { }") .build(module); - new ModuleBuilder("m2") + new ModuleBuilder(tb, "m2") .exports("pkg2") .classes("package pkg2; public class B { }") .build(module); Path upgradeModule = base.resolve("upgradeModule"); - new ModuleBuilder("m2") + new ModuleBuilder(tb, "m2") .exports("pkg2") .classes("package pkg2; public class BC { }") .build(upgradeModule); - new ModuleBuilder("m3") + new ModuleBuilder(tb, "m3") .exports("pkg3") .classes("package pkg3; public class DC { }") .build(upgradeModule); @@ -240,21 +241,21 @@ public class UpgradeModulePathTest extends ModuleTestBase { } @Test - void severalUpgradeModulePathsLastWin(Path base) throws Exception { + public void severalUpgradeModulePathsLastWin(Path base) throws Exception { final Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg1") .classes("package pkg1; public class E { }") .build(module); final Path upgradeModule1 = base.resolve("upgradeModule1"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg2") .classes("package pkg2; public class EC1 { }") .build(upgradeModule1); final Path upgradeModule2 = base.resolve("upgradeModule2"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("pkg2") .classes("package pkg2; public class EC2 { }") .build(upgradeModule2); diff --git a/langtools/test/tools/javac/modules/UsesTest.java b/langtools/test/tools/javac/modules/UsesTest.java index e35d1d4c076..510f70629c9 100644 --- a/langtools/test/tools/javac/modules/UsesTest.java +++ b/langtools/test/tools/javac/modules/UsesTest.java @@ -28,7 +28,7 @@ * @modules * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main - * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase + * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase * @run main UsesTest */ @@ -39,6 +39,7 @@ import java.util.Collection; import java.util.List; import toolbox.JavacTask; +import toolbox.ModuleBuilder; import toolbox.Task; import toolbox.ToolBox; @@ -49,7 +50,7 @@ public class UsesTest extends ModuleTestBase { } @Test - void testSimple(Path base) throws Exception { + public void testSimple(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses p.C; }", @@ -65,7 +66,7 @@ public class UsesTest extends ModuleTestBase { } @Test - void testSimpleInner(Path base) throws Exception { + public void testSimpleInner(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses p.C.Inner; }", @@ -81,7 +82,7 @@ public class UsesTest extends ModuleTestBase { } @Test - void testSimpleAnnotation(Path base) throws Exception { + public void testSimpleAnnotation(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses p.C; }", @@ -97,7 +98,7 @@ public class UsesTest extends ModuleTestBase { } @Test - void testPrivateService(Path base) throws Exception { + public void testPrivateService(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses p.C.A; uses p.C; }", @@ -119,7 +120,7 @@ public class UsesTest extends ModuleTestBase { } @Test - void testMulti(Path base) throws Exception { + public void testMulti(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p; }", @@ -138,13 +139,13 @@ public class UsesTest extends ModuleTestBase { } @Test - void testMultiOnModulePath(Path base) throws Exception { + public void testMultiOnModulePath(Path base) throws Exception { Path modules = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("p") .classes("package p; public class C { }") .build(modules); - new ModuleBuilder("m2") + new ModuleBuilder(tb, "m2") .requires("m1") .uses("p.C") .write(modules); @@ -158,13 +159,13 @@ public class UsesTest extends ModuleTestBase { } @Test - void testMultiOnModulePathInner(Path base) throws Exception { + public void testMultiOnModulePathInner(Path base) throws Exception { Path modules = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .exports("p") .classes("package p; public class C { public class Inner { } }") .build(modules); - new ModuleBuilder("m2") + new ModuleBuilder(tb, "m2") .requires("m1") .uses("p.C.Inner") .write(modules); @@ -178,7 +179,7 @@ public class UsesTest extends ModuleTestBase { } @Test - void testDuplicateUses(Path base) throws Exception { + public void testDuplicateUses(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m"), "module m { uses p.C; uses p.C; }", @@ -199,7 +200,7 @@ public class UsesTest extends ModuleTestBase { } @Test - void testServiceNotExist(Path base) throws Exception { + public void testServiceNotExist(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { uses p.NotExist; }", @@ -220,7 +221,7 @@ public class UsesTest extends ModuleTestBase { } @Test - void testUsesUnexportedService(Path base) throws Exception { + public void testUsesUnexportedService(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { }", @@ -244,7 +245,7 @@ public class UsesTest extends ModuleTestBase { } @Test - void testUsesUnexportedButProvidedService(Path base) throws Exception { + public void testUsesUnexportedButProvidedService(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("m1"), "module m1 { provides p.C with p.C; }", diff --git a/langtools/test/tools/javac/modules/XModuleTest.java b/langtools/test/tools/javac/modules/XModuleTest.java index 34465afb42f..1658f148a89 100644 --- a/langtools/test/tools/javac/modules/XModuleTest.java +++ b/langtools/test/tools/javac/modules/XModuleTest.java @@ -28,7 +28,7 @@ * @modules * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main - * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase + * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase * @run main XModuleTest */ @@ -37,7 +37,9 @@ import java.util.Arrays; import java.util.List; import toolbox.JavacTask; +import toolbox.ModuleBuilder; import toolbox.Task; +import toolbox.TestRunner; import toolbox.ToolBox; public class XModuleTest extends ModuleTestBase { @@ -47,7 +49,7 @@ public class XModuleTest extends ModuleTestBase { } @Test - void testCorrectXModule(Path base) throws Exception { + public void testCorrectXModule(Path base) throws Exception { //note: avoiding use of java.base, as that gets special handling on some places: Path src = base.resolve("src"); tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }"); @@ -67,7 +69,7 @@ public class XModuleTest extends ModuleTestBase { } @Test - void testSourcePath(Path base) throws Exception { + public void testSourcePath(Path base) throws Exception { //note: avoiding use of java.base, as that gets special handling on some places: Path src = base.resolve("src"); tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element, Other { }", "package javax.lang.model.element; interface Other { }"); @@ -87,7 +89,7 @@ public class XModuleTest extends ModuleTestBase { } @Test - void testClassPath(Path base) throws Exception { + public void testClassPath(Path base) throws Exception { Path cpSrc = base.resolve("cpSrc"); tb.writeJavaFiles(cpSrc, "package p; public interface Other { }"); Path cpClasses = base.resolve("cpClasses"); @@ -122,7 +124,7 @@ public class XModuleTest extends ModuleTestBase { } @Test - void testNoModuleInfoOnSourcePath(Path base) throws Exception { + public void testNoModuleInfoOnSourcePath(Path base) throws Exception { //note: avoiding use of java.base, as that gets special handling on some places: Path src = base.resolve("src"); tb.writeJavaFiles(src, @@ -147,7 +149,7 @@ public class XModuleTest extends ModuleTestBase { } @Test - void testNoModuleInfoInClassOutput(Path base) throws Exception { + public void testNoModuleInfoInClassOutput(Path base) throws Exception { //note: avoiding use of java.base, as that gets special handling on some places: Path srcMod = base.resolve("src-mod"); tb.writeJavaFiles(srcMod, @@ -187,7 +189,7 @@ public class XModuleTest extends ModuleTestBase { } @Test - void testModuleSourcePathXModule(Path base) throws Exception { + public void testModuleSourcePathXModule(Path base) throws Exception { //note: avoiding use of java.base, as that gets special handling on some places: Path src = base.resolve("src"); tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }"); @@ -210,7 +212,7 @@ public class XModuleTest extends ModuleTestBase { } @Test - void testXModuleTooMany(Path base) throws Exception { + public void testXModuleTooMany(Path base) throws Exception { //note: avoiding use of java.base, as that gets special handling on some places: Path src = base.resolve("src"); tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }"); @@ -234,9 +236,9 @@ public class XModuleTest extends ModuleTestBase { } @Test - void testWithModulePath(Path base) throws Exception { + public void testWithModulePath(Path base) throws Exception { Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .classes("package pkg1; public interface E { }") .build(module); @@ -251,7 +253,7 @@ public class XModuleTest extends ModuleTestBase { .writeAll(); //checks module bounds still exist - new ModuleBuilder("m2") + new ModuleBuilder(tb, "m2") .classes("package pkg2; public interface D { }") .build(module); @@ -275,14 +277,14 @@ public class XModuleTest extends ModuleTestBase { } @Test - void testWithUpgradeModulePath(Path base) throws Exception { + public void testWithUpgradeModulePath(Path base) throws Exception { Path module = base.resolve("modules"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .classes("package pkg1; public interface E { }") .build(module); Path upgrade = base.resolve("upgrade"); - new ModuleBuilder("m1") + new ModuleBuilder(tb, "m1") .classes("package pkg1; public interface D { }") .build(upgrade); diff --git a/langtools/test/tools/lib/toolbox/JavacTask.java b/langtools/test/tools/lib/toolbox/JavacTask.java index e2da5628969..72ff269d69b 100644 --- a/langtools/test/tools/lib/toolbox/JavacTask.java +++ b/langtools/test/tools/lib/toolbox/JavacTask.java @@ -102,6 +102,16 @@ public class JavacTask extends AbstractTask { return this; } + /** + * Sets the classpath. + * @param classpath the classpath + * @return this task object + */ + public JavacTask classpath(List classpath) { + this.classpath = classpath; + return this; + } + /** * Sets the sourcepath. * @param sourcepath the sourcepath @@ -125,6 +135,16 @@ public class JavacTask extends AbstractTask { return this; } + /** + * Sets the sourcepath. + * @param sourcepath the sourcepath + * @return this task object + */ + public JavacTask sourcepath(List sourcepath) { + this.sourcepath = sourcepath; + return this; + } + /** * Sets the output directory. * @param outdir the output directory @@ -187,6 +207,18 @@ public class JavacTask extends AbstractTask { return this; } + /** + * Sets the files to be compiled or analyzed. + * @param files the files + * @return this task object + */ + public JavacTask files(List files) { + this.files = files.stream() + .map(Path::toString) + .collect(Collectors.toList()); + return this; + } + /** * Sets the sources to be compiled or analyzed. * Each source string is converted into an in-memory object that diff --git a/langtools/test/tools/lib/toolbox/ModuleBuilder.java b/langtools/test/tools/lib/toolbox/ModuleBuilder.java new file mode 100644 index 00000000000..6c6ed659938 --- /dev/null +++ b/langtools/test/tools/lib/toolbox/ModuleBuilder.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package toolbox; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class ModuleBuilder { + + private final ToolBox tb; + private final String name; + private String requires = ""; + private String exports = ""; + private String uses = ""; + private String provides = ""; + private String modulePath = ""; + private List content = new ArrayList<>(); + + public ModuleBuilder(ToolBox tb, String name) { + this.tb = tb; + this.name = name; + } + + public ModuleBuilder requiresPublic(String requires, Path... modulePath) { + return requires("public " + requires, modulePath); + } + + public ModuleBuilder requires(String requires, Path... modulePath) { + this.requires += " requires " + requires + ";\n"; + this.modulePath += Arrays.stream(modulePath) + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + return this; + } + + public ModuleBuilder exportsTo(String pkg, String module) { + return exports(pkg + " to " + module); + } + + public ModuleBuilder exports(String pkg) { + this.exports += " exports " + pkg + ";\n"; + return this; + } + + public ModuleBuilder uses(String uses) { + this.uses += " uses " + uses + ";\n"; + return this; + } + + public ModuleBuilder provides(String service, String implementation) { + this.provides += " provides " + service + " with " + implementation + ";\n"; + return this; + } + + public ModuleBuilder classes(String... content) { + this.content.addAll(Arrays.asList(content)); + return this; + } + + public Path write(Path where) throws IOException { + Files.createDirectories(where); + List sources = new ArrayList<>(); + sources.add("module " + name + "{" + + requires + + exports + + uses + + provides + + "}"); + sources.addAll(content); + Path moduleSrc = where.resolve(name + "/src"); + tb.writeJavaFiles(moduleSrc, sources.toArray(new String[]{})); + return moduleSrc; + } + + public void build(Path where) throws IOException { + Path moduleSrc = write(where); + new JavacTask(tb) + .outdir(where.resolve(name)) + .options("-mp", modulePath) + .files(tb.findJavaFiles(moduleSrc)) + .run() + .writeAll(); + } +} diff --git a/langtools/test/tools/lib/toolbox/TestRunner.java b/langtools/test/tools/lib/toolbox/TestRunner.java index 22034730405..f0a921ef127 100644 --- a/langtools/test/tools/lib/toolbox/TestRunner.java +++ b/langtools/test/tools/lib/toolbox/TestRunner.java @@ -35,15 +35,16 @@ import java.util.function.Function; * Utility class to manage and execute sub-tests within a test. * * This class does the following: - * i. invokes those test methods annotated with @Test - * ii. keeps track of successful and failed tests - * iii. throws an Exception if any test fails. - * iv. provides a test summary at the end of the run. - * + *
          + *
        • invokes those test methods annotated with @Test + *
        • keeps track of successful and failed tests + *
        • throws an Exception if any test fails. + *
        • provides a test summary at the end of the run. + *
        + * Tests must extend this class, annotate the test methods * with @Test and call one of the runTests method. */ - public abstract class TestRunner { /** Marker annotation for test cases. */ @Retention(RetentionPolicy.RUNTIME) @@ -54,7 +55,7 @@ public abstract class TestRunner { public String testName = null; - final PrintStream out; + protected PrintStream out; /** * Constructs the Object. @@ -66,18 +67,18 @@ public abstract class TestRunner { /** * Invoke all methods annotated with @Test. - * @throws java.lang.Exception + * @throws java.lang.Exception if any errors occur */ - public void runTests() throws Exception { + protected void runTests() throws Exception { runTests(f -> new Object[0]); } /** * Invoke all methods annotated with @Test. - * @param f a lambda expression to specify arguments. - * @throws java.lang.Exception + * @param f a lambda expression to specify arguments for the test method + * @throws java.lang.Exception if any errors occur */ - public void runTests(Function f) throws Exception { + protected void runTests(Function f) throws Exception { for (Method m : getClass().getDeclaredMethods()) { Annotation a = m.getAnnotation(Test.class); if (a != null) { diff --git a/langtools/test/tools/lib/toolbox/ToolBox.java b/langtools/test/tools/lib/toolbox/ToolBox.java index 287313f9c42..5ac6117d8bb 100644 --- a/langtools/test/tools/lib/toolbox/ToolBox.java +++ b/langtools/test/tools/lib/toolbox/ToolBox.java @@ -41,6 +41,7 @@ import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -49,6 +50,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -315,7 +317,7 @@ public class ToolBox { * Reads the lines of a file. * The file is read using the default character encoding. * @param path the file to be read - * @return the lines of the file. + * @return the lines of the file * @throws IOException if an error occurred while reading the file */ public List readAllLines(String path) throws IOException { @@ -326,7 +328,7 @@ public class ToolBox { * Reads the lines of a file. * The file is read using the default character encoding. * @param path the file to be read - * @return the lines of the file. + * @return the lines of the file * @throws IOException if an error occurred while reading the file */ public List readAllLines(Path path) throws IOException { @@ -348,7 +350,7 @@ public class ToolBox { * Reads the lines of a file using the given encoding. * @param path the file to be read * @param encoding the encoding to be used to read the file - * @return the lines of the file. + * @return the lines of the file * @throws IOException if an error occurred while reading the file */ public List readAllLines(Path path, String encoding) throws IOException { @@ -359,6 +361,30 @@ public class ToolBox { return (encoding == null) ? Charset.defaultCharset() : Charset.forName(encoding); } + /** + * Find .java files in one or more directories. + *

        Similar to the shell "find" command: {@code find paths -name \*.java}. + * @param paths the directories in which to search for .java files + * @return the .java files found + * @throws IOException if an error occurred while searching for files + */ + public Path[] findJavaFiles(Path... paths) throws IOException { + Set files = new TreeSet<>(); // use TreeSet to force a consistent order + for (Path p : paths) { + Files.walkFileTree(p, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + if (file.getFileName().toString().endsWith(".java")) { + files.add(file); + } + return FileVisitResult.CONTINUE; + } + }); + } + return files.toArray(new Path[files.size()]); + } + /** * Writes a file containing the given content. * Any necessary directories for the file will be created. From b3854d58300ec1e9518d1aa266e374577f15edd1 Mon Sep 17 00:00:00 2001 From: Anthony Scarpino Date: Mon, 2 May 2016 16:45:38 -0700 Subject: [PATCH 217/222] 8140422: Add mechanism to allow non default root CAs to be not subject to algorithm restrictions Reviewed-by: mullan, xuelei --- jdk/make/gendata/Gendata-java.base.gmk | 14 +- .../provider/certpath/AlgorithmChecker.java | 146 +++--- .../certpath/PKIXMasterCertPathValidator.java | 4 +- .../util/AbstractAlgorithmConstraints.java | 19 +- .../security/util/AlgorithmDecomposer.java | 70 ++- .../sun/security/util/AnchorCertificates.java | 101 +++++ .../util/CertConstraintParameters.java | 59 +++ .../util/DisabledAlgorithmConstraints.java | 420 ++++++++++++++---- .../util/LegacyAlgorithmConstraints.java | 9 +- .../sun/security/x509/X509CertImpl.java | 11 +- .../share/conf/security/java.security | 30 +- .../sun/security/tools/jarsigner/Warning.java | 2 +- 12 files changed, 694 insertions(+), 191 deletions(-) create mode 100644 jdk/src/java.base/share/classes/sun/security/util/AnchorCertificates.java create mode 100644 jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java diff --git a/jdk/make/gendata/Gendata-java.base.gmk b/jdk/make/gendata/Gendata-java.base.gmk index d94ec3404c0..5c6de721b64 100644 --- a/jdk/make/gendata/Gendata-java.base.gmk +++ b/jdk/make/gendata/Gendata-java.base.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ include GendataPolicyJars.gmk GENDATA_UNINAME := $(JDK_OUTPUTDIR)/modules/java.base/java/lang/uniName.dat $(GENDATA_UNINAME): $(JDK_TOPDIR)/make/data/unicodedata/UnicodeData.txt $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(@D) + $(call MakeDir, $(@D)) $(TOOL_CHARACTERNAME) $< $@ TARGETS += $(GENDATA_UNINAME) @@ -51,7 +51,7 @@ TARGETS += $(GENDATA_UNINAME) GENDATA_CURDATA := $(JDK_OUTPUTDIR)/modules/java.base/java/util/currency.data $(GENDATA_CURDATA): $(JDK_TOPDIR)/make/data/currency/CurrencyData.properties $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(@D) + $(call MakeDir, $(@D)) $(RM) $@ $(TOOL_GENERATECURRENCYDATA) -o $@.tmp < $< $(MV) $@.tmp $@ @@ -67,10 +67,10 @@ GENDATA_JAVA_SECURITY := $(SUPPORT_OUTPUTDIR)/modules_conf/java.base/security/ja # RESTRICTED_PKGS_SRC is optionally set in custom extension for this makefile $(GENDATA_JAVA_SECURITY): $(BUILD_TOOLS) $(GENDATA_JAVA_SECURITY_SRC) $(RESTRICTED_PKGS_SRC) - $(ECHO) "Generating java.security" - $(MKDIR) -p $(@D) + $(call LogInfo, Generating java.security) + $(call MakeDir, $(@D)) $(TOOL_MAKEJAVASECURITY) $(GENDATA_JAVA_SECURITY_SRC) $@ $(OPENJDK_TARGET_OS) \ - $(OPENJDK_TARGET_CPU_ARCH) $(RESTRICTED_PKGS_SRC) || exit 1 + $(OPENJDK_TARGET_CPU_ARCH) $(RESTRICTED_PKGS_SRC) TARGETS += $(GENDATA_JAVA_SECURITY) @@ -78,7 +78,7 @@ TARGETS += $(GENDATA_JAVA_SECURITY) $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/classlist: \ $(JDK_TOPDIR)/make/data/classlist/classlist.$(OPENJDK_TARGET_OS) - $(MKDIR) -p $(@D) + $(call MakeDir, $(@D)) $(RM) $@ $@.tmp $(TOOL_ADDJSUM) $< $@.tmp $(MV) $@.tmp $@ diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java index b71121423d8..b210d18e073 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. * 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,12 +31,10 @@ import java.util.Collection; import java.util.Collections; import java.util.Set; import java.util.EnumSet; -import java.util.HashSet; import java.math.BigInteger; import java.security.PublicKey; import java.security.KeyFactory; import java.security.AlgorithmParameters; -import java.security.NoSuchAlgorithmException; import java.security.GeneralSecurityException; import java.security.cert.Certificate; import java.security.cert.X509CRL; @@ -48,10 +46,13 @@ import java.security.cert.CertificateException; import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.PKIXReason; -import java.io.IOException; -import java.security.interfaces.*; -import java.security.spec.*; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAPublicKeySpec; +import sun.security.util.AnchorCertificates; +import sun.security.util.CertConstraintParameters; +import sun.security.util.Debug; import sun.security.util.DisabledAlgorithmConstraints; import sun.security.x509.X509CertImpl; import sun.security.x509.X509CRLImpl; @@ -69,6 +70,7 @@ import sun.security.x509.AlgorithmId; * @see PKIXParameters */ public final class AlgorithmChecker extends PKIXCertPathChecker { + private static final Debug debug = Debug.getInstance("certpath"); private final AlgorithmConstraints constraints; private final PublicKey trustedPubKey; @@ -88,6 +90,14 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { certPathDefaultConstraints = new DisabledAlgorithmConstraints( DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS); + // If there is no "cacerts" keyword, then disable anchor checking + private static final boolean publicCALimits = + certPathDefaultConstraints.checkProperty("jdkCA"); + + // If anchor checking enabled, this will be true if the trust anchor + // has a match in the cacerts file + private boolean trustedMatch = false; + /** * Create a new AlgorithmChecker with the algorithm * constraints specified in security property @@ -136,6 +146,11 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { if (anchor.getTrustedCert() != null) { this.trustedPubKey = anchor.getTrustedCert().getPublicKey(); + // Check for anchor certificate restrictions + trustedMatch = checkFingerprint(anchor.getTrustedCert()); + if (trustedMatch && debug != null) { + debug.println("trustedMatch = true"); + } } else { this.trustedPubKey = anchor.getCAPublicKey(); } @@ -144,6 +159,19 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { this.constraints = constraints; } + // Check this 'cert' for restrictions in the AnchorCertificates + // trusted certificates list + private static boolean checkFingerprint(X509Certificate cert) { + if (!publicCALimits) { + return false; + } + + if (debug != null) { + debug.println("AlgorithmChecker.contains: " + cert.getSigAlgName()); + } + return AnchorCertificates.contains(cert); + } + @Override public void init(boolean forward) throws CertPathValidatorException { // Note that this class does not support forward mode. @@ -181,36 +209,8 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { return; } - X509CertImpl x509Cert = null; - try { - x509Cert = X509CertImpl.toImpl((X509Certificate)cert); - } catch (CertificateException ce) { - throw new CertPathValidatorException(ce); - } - - PublicKey currPubKey = x509Cert.getPublicKey(); - String currSigAlg = x509Cert.getSigAlgName(); - - AlgorithmId algorithmId = null; - try { - algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG); - } catch (CertificateException ce) { - throw new CertPathValidatorException(ce); - } - - AlgorithmParameters currSigAlgParams = algorithmId.getParameters(); - - // Check the current signature algorithm - if (!constraints.permits( - SIGNATURE_PRIMITIVE_SET, - currSigAlg, currSigAlgParams)) { - throw new CertPathValidatorException( - "Algorithm constraints check failed: " + currSigAlg, - null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); - } - // check the key usage and key size - boolean[] keyUsage = x509Cert.getKeyUsage(); + boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage(); if (keyUsage != null && keyUsage.length < 9) { throw new CertPathValidatorException( "incorrect KeyUsage extension", @@ -248,27 +248,67 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { if (primitives.isEmpty()) { throw new CertPathValidatorException( - "incorrect KeyUsage extension", + "incorrect KeyUsage extension bits", null, null, -1, PKIXReason.INVALID_KEY_USAGE); } } - if (!constraints.permits(primitives, currPubKey)) { - throw new CertPathValidatorException( - "algorithm constraints check failed", - null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + PublicKey currPubKey = cert.getPublicKey(); + + // Check against DisabledAlgorithmConstraints certpath constraints. + // permits() will throw exception on failure. + certPathDefaultConstraints.permits(primitives, + new CertConstraintParameters((X509Certificate)cert, + trustedMatch)); + // new CertConstraintParameters(x509Cert, trustedMatch)); + // If there is no previous key, set one and exit + if (prevPubKey == null) { + prevPubKey = currPubKey; + return; + } + + X509CertImpl x509Cert; + AlgorithmId algorithmId; + try { + x509Cert = X509CertImpl.toImpl((X509Certificate)cert); + algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG); + } catch (CertificateException ce) { + throw new CertPathValidatorException(ce); + } + + AlgorithmParameters currSigAlgParams = algorithmId.getParameters(); + String currSigAlg = x509Cert.getSigAlgName(); + + // If 'constraints' is not of DisabledAlgorithmConstraints, check all + // everything individually + if (!(constraints instanceof DisabledAlgorithmConstraints)) { + // Check the current signature algorithm + if (!constraints.permits( + SIGNATURE_PRIMITIVE_SET, + currSigAlg, currSigAlgParams)) { + throw new CertPathValidatorException( + "Algorithm constraints check failed on signature " + + "algorithm: " + currSigAlg, null, null, -1, + BasicReason.ALGORITHM_CONSTRAINED); + } + + if (!constraints.permits(primitives, currPubKey)) { + throw new CertPathValidatorException( + "Algorithm constraints check failed on keysize: " + + sun.security.util.KeyUtil.getKeySize(currPubKey), + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + } } // Check with previous cert for signature algorithm and public key if (prevPubKey != null) { - if (currSigAlg != null) { - if (!constraints.permits( - SIGNATURE_PRIMITIVE_SET, - currSigAlg, prevPubKey, currSigAlgParams)) { - throw new CertPathValidatorException( - "Algorithm constraints check failed: " + currSigAlg, - null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); - } + if (!constraints.permits( + SIGNATURE_PRIMITIVE_SET, + currSigAlg, prevPubKey, currSigAlgParams)) { + throw new CertPathValidatorException( + "Algorithm constraints check failed on " + + "signature algorithm: " + currSigAlg, + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } // Inherit key parameters from previous key @@ -282,7 +322,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { DSAParams params = ((DSAPublicKey)prevPubKey).getParams(); if (params == null) { throw new CertPathValidatorException( - "Key parameters missing"); + "Key parameters missing from public key."); } try { @@ -330,6 +370,11 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { // Don't bother to change the trustedPubKey. if (anchor.getTrustedCert() != null) { prevPubKey = anchor.getTrustedCert().getPublicKey(); + // Check for anchor certificate restrictions + trustedMatch = checkFingerprint(anchor.getTrustedCert()); + if (trustedMatch && debug != null) { + debug.println("trustedMatch = true"); + } } else { prevPubKey = anchor.getCAPublicKey(); } @@ -370,7 +415,8 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { if (!certPathDefaultConstraints.permits( SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) { throw new CertPathValidatorException( - "algorithm check failed: " + sigAlgName + " is disabled", + "Algorithm constraints check failed on signature algorithm: " + + sigAlgName + " is disabled", null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java index cfffba8329a..e85ef2d0303 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java @@ -131,8 +131,8 @@ class PKIXMasterCertPathValidator { } catch (CertPathValidatorException cpve) { throw new CertPathValidatorException(cpve.getMessage(), - cpve.getCause(), cpOriginal, cpSize - (i + 1), - cpve.getReason()); + (cpve.getCause() != null) ? cpve.getCause() : cpve, + cpOriginal, cpSize - (i + 1), cpve.getReason()); } } diff --git a/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java b/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java index 94670e40324..2825e14254f 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java +++ b/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. * 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,7 +29,6 @@ import java.security.AccessController; import java.security.AlgorithmConstraints; import java.security.PrivilegedAction; import java.security.Security; -import java.util.Map; import java.util.Set; /** @@ -45,8 +44,7 @@ public abstract class AbstractAlgorithmConstraints } // Get algorithm constraints from the specified security property. - private static void loadAlgorithmsMap(Map algorithmsMap, - String propertyName) { + static String[] getAlgorithms(String propertyName) { String property = AccessController.doPrivileged( (PrivilegedAction) () -> Security.getProperty( propertyName)); @@ -68,18 +66,7 @@ public abstract class AbstractAlgorithmConstraints if (algorithmsInProperty == null) { algorithmsInProperty = new String[0]; } - algorithmsMap.put(propertyName, algorithmsInProperty); - } - - static String[] getAlgorithms(Map algorithmsMap, - String propertyName) { - synchronized (algorithmsMap) { - if (!algorithmsMap.containsKey(propertyName)) { - loadAlgorithmsMap(algorithmsMap, propertyName); - } - - return algorithmsMap.get(propertyName); - } + return algorithmsInProperty; } static boolean checkAlgorithm(String[] algorithms, String algorithm, diff --git a/jdk/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java b/jdk/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java index 4410a3102be..bff76cf1721 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java +++ b/jdk/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,19 +40,7 @@ public class AlgorithmDecomposer { private static final Pattern pattern = Pattern.compile("with|and|(? - * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA" - * so that we can check the "SHA1" and "RSA" algorithm constraints - * separately. - *

        - * Please override the method if need to support more name pattern. - */ - public Set decompose(String algorithm) { - if (algorithm == null || algorithm.length() == 0) { - return new HashSet<>(); - } + private static Set decomposeImpl(String algorithm) { // algorithm/mode/padding String[] transTockens = transPattern.split(algorithm); @@ -79,6 +67,24 @@ public class AlgorithmDecomposer { elements.add(token); } } + return elements; + } + + /** + * Decompose the standard algorithm name into sub-elements. + *

        + * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA" + * so that we can check the "SHA1" and "RSA" algorithm constraints + * separately. + *

        + * Please override the method if need to support more name pattern. + */ + public Set decompose(String algorithm) { + if (algorithm == null || algorithm.length() == 0) { + return new HashSet<>(); + } + + Set elements = decomposeImpl(algorithm); // In Java standard algorithm name specification, for different // purpose, the SHA-1 and SHA-2 algorithm names are different. For @@ -130,4 +136,40 @@ public class AlgorithmDecomposer { return elements; } + private static void hasLoop(Set elements, String find, String replace) { + if (elements.contains(find)) { + if (!elements.contains(replace)) { + elements.add(replace); + } + elements.remove(find); + } + } + + /* + * This decomposes a standard name into sub-elements with a consistent + * message digest algorithm name to avoid overly complicated checking. + */ + public static Set decomposeOneHash(String algorithm) { + if (algorithm == null || algorithm.length() == 0) { + return new HashSet<>(); + } + + Set elements = decomposeImpl(algorithm); + + hasLoop(elements, "SHA-1", "SHA1"); + hasLoop(elements, "SHA-224", "SHA224"); + hasLoop(elements, "SHA-256", "SHA256"); + hasLoop(elements, "SHA-384", "SHA384"); + hasLoop(elements, "SHA-512", "SHA512"); + + return elements; + } + + /* + * The provided message digest algorithm name will return a consistent + * naming scheme. + */ + public static String hashName(String algorithm) { + return algorithm.replace("-", ""); + } } diff --git a/jdk/src/java.base/share/classes/sun/security/util/AnchorCertificates.java b/jdk/src/java.base/share/classes/sun/security/util/AnchorCertificates.java new file mode 100644 index 00000000000..6bc003054d1 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/security/util/AnchorCertificates.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.security.util; + +import java.io.File; +import java.io.FileInputStream; +import java.security.AccessController; +import java.security.KeyStore; +import java.security.PrivilegedAction; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.HashSet; + +import sun.security.x509.X509CertImpl; + +/** + * The purpose of this class is to determine the trust anchor certificates is in + * the cacerts file. This is used for PKIX CertPath checking. + */ +public class AnchorCertificates { + + private static final Debug debug = Debug.getInstance("certpath"); + private static final String HASH = "SHA-256"; + private static HashSet certs; + + static { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + File f = new File(System.getProperty("java.home"), + "lib/security/cacerts"); + KeyStore cacerts; + try { + cacerts = KeyStore.getInstance("JKS"); + try (FileInputStream fis = new FileInputStream(f)) { + cacerts.load(fis, "changeit".toCharArray()); + certs = new HashSet<>(); + Enumeration list = cacerts.aliases(); + String alias; + while (list.hasMoreElements()) { + alias = list.nextElement(); + // Check if this cert is labeled a trust anchor. + if (alias.contains(" [jdk")) { + X509Certificate cert = (X509Certificate) cacerts + .getCertificate(alias); + certs.add(X509CertImpl.getFingerprint(HASH, cert)); + } + } + } + } catch (Exception e) { + if (debug != null) { + debug.println("Error parsing cacerts"); + } + e.printStackTrace(); + } + return null; + } + }); + } + + /** + * Checks if a certificate is a trust anchor. + * + * @param cert the certificate to check + * @return true if the certificate is trusted. + */ + public static boolean contains(X509Certificate cert) { + String key = X509CertImpl.getFingerprint(HASH, cert); + boolean result = certs.contains(key); + if (result && debug != null) { + debug.println("AnchorCertificate.contains: matched " + + cert.getSubjectDN()); + } + return result; + } + + private AnchorCertificates() {} +} diff --git a/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java b/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java new file mode 100644 index 00000000000..9f7a938dede --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 sun.security.util; + +import java.security.cert.X509Certificate; + +/** + * This class is a wrapper for keeping state and passing objects between PKIX, + * AlgorithmChecker, and DisabledAlgorithmConstraints. + */ +public class CertConstraintParameters { + // A certificate being passed to check against constraints. + private final X509Certificate cert; + + // This is true if the trust anchor in the certificate chain matches a cert + // in AnchorCertificates + private final boolean trustedMatch; + + public CertConstraintParameters(X509Certificate c, boolean match) { + cert = c; + trustedMatch = match; + } + + public CertConstraintParameters(X509Certificate c) { + this(c, false); + } + + // Returns if the trust anchor has a match if anchor checking is enabled. + public boolean isTrustedMatch() { + return trustedMatch; + } + + public X509Certificate getCertificate() { + return cert; + } +} diff --git a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java index fd4b198ce11..d4b2a4054b3 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +++ b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,12 +28,14 @@ package sun.security.util; import java.security.CryptoPrimitive; import java.security.AlgorithmParameters; import java.security.Key; -import java.util.Locale; -import java.util.Set; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorException.BasicReason; +import java.security.cert.X509Certificate; import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; import java.util.regex.Matcher; @@ -44,6 +46,7 @@ import java.util.regex.Matcher; * for the syntax of the disabled algorithm string. */ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { + private static final Debug debug = Debug.getInstance("certpath"); // the known security property, jdk.certpath.disabledAlgorithms public static final String PROPERTY_CERTPATH_DISABLED_ALGS = @@ -53,13 +56,8 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { public static final String PROPERTY_TLS_DISABLED_ALGS = "jdk.tls.disabledAlgorithms"; - private static final Map disabledAlgorithmsMap = - new HashMap<>(); - private static final Map keySizeConstraintsMap = - new HashMap<>(); - private final String[] disabledAlgorithms; - private final KeySizeConstraints keySizeConstraints; + private final Constraints algorithmConstraints; /** * Initialize algorithm constraints with the specified security property. @@ -74,11 +72,14 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { public DisabledAlgorithmConstraints(String propertyName, AlgorithmDecomposer decomposer) { super(decomposer); - disabledAlgorithms = getAlgorithms(disabledAlgorithmsMap, propertyName); - keySizeConstraints = getKeySizeConstraints(disabledAlgorithms, - propertyName); + disabledAlgorithms = getAlgorithms(propertyName); + algorithmConstraints = new Constraints(disabledAlgorithms); } + /* + * This only checks if the algorithm has been completely disabled. If + * there are keysize or other limit, this method allow the algorithm. + */ @Override public final boolean permits(Set primitives, String algorithm, AlgorithmParameters parameters) { @@ -91,11 +92,19 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { return checkAlgorithm(disabledAlgorithms, algorithm, decomposer); } + /* + * Checks if the key algorithm has been disabled or constraints have been + * placed on the key. + */ @Override public final boolean permits(Set primitives, Key key) { return checkConstraints(primitives, "", key, null); } + /* + * Checks if the key algorithm has been disabled or if constraints have + * been placed on the key. + */ @Override public final boolean permits(Set primitives, String algorithm, Key key, AlgorithmParameters parameters) { @@ -107,7 +116,39 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { return checkConstraints(primitives, algorithm, key, parameters); } - // Check algorithm constraints + /* + * Check if a x509Certificate object is permitted. Check if all + * algorithms are allowed, certificate constraints, and the + * public key against key constraints. + * + * Uses new style permit() which throws exceptions. + */ + public final void permits(Set primitives, + CertConstraintParameters cp) throws CertPathValidatorException { + checkConstraints(primitives, cp); + } + + /* + * Check if Certificate object is within the constraints. + * Uses new style permit() which throws exceptions. + */ + public final void permits(Set primitives, + X509Certificate cert) throws CertPathValidatorException { + checkConstraints(primitives, new CertConstraintParameters(cert)); + } + + // Check if a string is contained inside the property + public boolean checkProperty(String param) { + param = param.toLowerCase(Locale.ENGLISH); + for (String block : disabledAlgorithms) { + if (block.toLowerCase(Locale.ENGLISH).indexOf(param) >= 0) { + return true; + } + } + return false; + } + + // Check algorithm constraints with key and algorithm private boolean checkConstraints(Set primitives, String algorithm, Key key, AlgorithmParameters parameters) { @@ -116,7 +157,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { throw new IllegalArgumentException("The key cannot be null"); } - // check the target algorithm + // check the signature algorithm if (algorithm != null && algorithm.length() != 0) { if (!permits(primitives, algorithm, parameters)) { return false; @@ -129,97 +170,203 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } // check the key constraints - if (keySizeConstraints.disables(key)) { - return false; - } - - return true; + return algorithmConstraints.permits(key); } - private static KeySizeConstraints getKeySizeConstraints( - String[] disabledAlgorithms, String propertyName) { - synchronized (keySizeConstraintsMap) { - if(!keySizeConstraintsMap.containsKey(propertyName)) { - // map the key constraints - KeySizeConstraints keySizeConstraints = - new KeySizeConstraints(disabledAlgorithms); - keySizeConstraintsMap.put(propertyName, keySizeConstraints); - } + /* + * Check algorithm constraints with Certificate + * Uses new style permit() which throws exceptions. + */ + private void checkConstraints(Set primitives, + CertConstraintParameters cp) throws CertPathValidatorException { - return keySizeConstraintsMap.get(propertyName); + X509Certificate cert = cp.getCertificate(); + String algorithm = cert.getSigAlgName(); + + // Check signature algorithm is not disabled + if (!permits(primitives, algorithm, null)) { + throw new CertPathValidatorException( + "Algorithm constraints check failed on disabled "+ + "signature algorithm: " + algorithm, + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } + + // Check key algorithm is not disabled + if (!permits(primitives, cert.getPublicKey().getAlgorithm(), null)) { + throw new CertPathValidatorException( + "Algorithm constraints check failed on disabled "+ + "public key algorithm: " + algorithm, + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + } + + // Check the certificate and key constraints + algorithmConstraints.permits(cp); + } /** - * key constraints + * Key and Certificate Constraints + * + * The complete disabling of an algorithm is not handled by Constraints or + * Constraint classes. That is addressed with + * permit(Set, String, AlgorithmParameters) + * + * When passing a Key to permit(), the boolean return values follow the + * same as the interface class AlgorithmConstraints.permit(). This is to + * maintain compatibility: + * 'true' means the operation is allowed. + * 'false' means it failed the constraints and is disallowed. + * + * When passing CertConstraintParameters through permit(), an exception + * will be thrown on a failure to better identify why the operation was + * disallowed. */ - private static class KeySizeConstraints { - private static final Pattern pattern = Pattern.compile( - "(\\S+)\\s+keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)"); - private Map> constraintsMap = - Collections.synchronizedMap( - new HashMap>()); + private static class Constraints { + private Map> constraintsMap = new HashMap<>(); + private static final Pattern keySizePattern = Pattern.compile( + "keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)"); - public KeySizeConstraints(String[] restrictions) { - for (String restriction : restrictions) { - if (restriction == null || restriction.isEmpty()) { + public Constraints(String[] constraintArray) { + for (String constraintEntry : constraintArray) { + if (constraintEntry == null || constraintEntry.isEmpty()) { continue; } - Matcher matcher = pattern.matcher(restriction); - if (matcher.matches()) { - String algorithm = matcher.group(1); + constraintEntry = constraintEntry.trim(); + if (debug != null) { + debug.println("Constraints: " + constraintEntry); + } - KeySizeConstraint.Operator operator = - KeySizeConstraint.Operator.of(matcher.group(2)); - int length = Integer.parseInt(matcher.group(3)); + // Check if constraint is a complete disabling of an + // algorithm or has conditions. + String algorithm; + String policy; + int space = constraintEntry.indexOf(' '); + if (space > 0) { + algorithm = AlgorithmDecomposer.hashName( + constraintEntry.substring(0, space). + toUpperCase(Locale.ENGLISH)); + policy = constraintEntry.substring(space + 1); + } else { + constraintsMap.computeIfAbsent( + constraintEntry.toUpperCase(Locale.ENGLISH), + k -> new HashSet<>()); + continue; + } - algorithm = algorithm.toLowerCase(Locale.ENGLISH); + // Convert constraint conditions into Constraint classes + Constraint c, lastConstraint = null; + // Allow only one jdkCA entry per constraint entry + boolean jdkCALimit = false; - synchronized (constraintsMap) { - if (!constraintsMap.containsKey(algorithm)) { - constraintsMap.put(algorithm, - new HashSet()); + for (String entry : policy.split("&")) { + entry = entry.trim(); + + Matcher matcher = keySizePattern.matcher(entry); + if (matcher.matches()) { + if (debug != null) { + debug.println("Constraints set to keySize: " + + entry); } + c = new KeySizeConstraint(algorithm, + KeySizeConstraint.Operator.of(matcher.group(1)), + Integer.parseInt(matcher.group(2))); - Set constraintSet = - constraintsMap.get(algorithm); - KeySizeConstraint constraint = - new KeySizeConstraint(operator, length); - constraintSet.add(constraint); + } else if (entry.equalsIgnoreCase("jdkCA")) { + if (debug != null) { + debug.println("Constraints set to jdkCA."); + } + if (jdkCALimit) { + throw new IllegalArgumentException("Only one " + + "jdkCA entry allowed in property. " + + "Constraint: " + constraintEntry); + } + c = new jdkCAConstraint(algorithm); + jdkCALimit = true; + } else { + throw new IllegalArgumentException("Error in security" + + " property. Constraint unknown: " + entry); } + + // Link multiple conditions for a single constraint + // into a linked list. + if (lastConstraint == null) { + if (!constraintsMap.containsKey(algorithm)) { + constraintsMap.putIfAbsent(algorithm, + new HashSet<>()); + } + constraintsMap.get(algorithm).add(c); + } else { + lastConstraint.nextConstraint = c; + } + lastConstraint = c; } } } - // Does this KeySizeConstraints disable the specified key? - public boolean disables(Key key) { - String algorithm = key.getAlgorithm().toLowerCase(Locale.ENGLISH); - synchronized (constraintsMap) { - if (constraintsMap.containsKey(algorithm)) { - Set constraintSet = - constraintsMap.get(algorithm); - for (KeySizeConstraint constraint : constraintSet) { - if (constraint.disables(key)) { - return true; - } + // Get applicable constraints based off the signature algorithm + private Set getConstraints(String algorithm) { + return constraintsMap.get(algorithm); + } + + // Check if KeySizeConstraints permit the specified key + public boolean permits(Key key) { + Set set = getConstraints(key.getAlgorithm()); + if (set == null) { + return true; + } + for (Constraint constraint : set) { + if (!constraint.permits(key)) { + if (debug != null) { + debug.println("keySizeConstraint: failed key " + + "constraint check " + KeyUtil.getKeySize(key)); } + return false; } } + return true; + } - return false; + // Check if constraints permit this cert. + public void permits(CertConstraintParameters cp) + throws CertPathValidatorException { + X509Certificate cert = cp.getCertificate(); + + if (debug != null) { + debug.println("Constraints.permits(): " + cert.getSigAlgName()); + } + + // Get all signature algorithms to check for constraints + Set algorithms = + AlgorithmDecomposer.decomposeOneHash(cert.getSigAlgName()); + if (algorithms == null || algorithms.isEmpty()) { + return; + } + + // Attempt to add the public key algorithm to the set + algorithms.add(cert.getPublicKey().getAlgorithm()); + + // Check all applicable constraints + for (String algorithm : algorithms) { + Set set = getConstraints(algorithm); + if (set == null) { + continue; + } + for (Constraint constraint : set) { + constraint.permits(cp); + } + } } } - /** - * Key size constraint. - * - * e.g. "keysize <= 1024" - */ - private static class KeySizeConstraint { + // Abstract class for algorithm constraint checking + private abstract static class Constraint { + String algorithm; + Constraint nextConstraint = null; + // operator - static enum Operator { + enum Operator { EQ, // "==" NE, // "!=" LT, // "<" @@ -243,16 +390,77 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { return GE; } - throw new IllegalArgumentException( - s + " is not a legal Operator"); + throw new IllegalArgumentException("Error in security " + + "property. " + s + " is not a legal Operator"); } } + /** + * Check if an algorithm constraint permit this key to be used. + * @param key Public key + * @return true if constraints do not match + */ + public boolean permits(Key key) { + return true; + } + + /** + * Check if an algorithm constraint is permit this certificate to + * be used. + * @param cp CertificateParameter containing certificate and state info + * @return true if constraints do not match + */ + public abstract void permits(CertConstraintParameters cp) + throws CertPathValidatorException; + } + + /* + * This class contains constraints dealing with the certificate chain + * of the certificate. + */ + private static class jdkCAConstraint extends Constraint { + jdkCAConstraint(String algo) { + algorithm = algo; + } + + /* + * Check if each constraint fails and check if there is a linked + * constraint Any permitted constraint will exit the linked list + * to allow the operation. + */ + public void permits(CertConstraintParameters cp) + throws CertPathValidatorException { + if (debug != null) { + debug.println("jdkCAConstraints.permits(): " + algorithm); + } + + // Return false if the chain has a trust anchor in cacerts + if (cp.isTrustedMatch()) { + if (nextConstraint != null) { + nextConstraint.permits(cp); + return; + } + throw new CertPathValidatorException( + "Algorithm constraints check failed on certificate " + + "anchor limits", + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + } + } + } + + + /* + * This class contains constraints dealing with the key size + * support limits per algorithm. e.g. "keySize <= 1024" + */ + private static class KeySizeConstraint extends Constraint { + private int minSize; // the minimal available key size private int maxSize; // the maximal available key size private int prohibitedSize = -1; // unavailable key sizes - public KeySizeConstraint(Operator operator, int length) { + public KeySizeConstraint(String algo, Operator operator, int length) { + algorithm = algo; switch (operator) { case EQ: // an unavailable key size this.minSize = 0; @@ -286,21 +494,59 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } } - // Does this key constraint disable the specified key? - public boolean disables(Key key) { - int size = KeyUtil.getKeySize(key); + /* + * If we are passed a certificate, extract the public key and use it. + * + * Check if each constraint fails and check if there is a linked + * constraint Any permitted constraint will exit the linked list + * to allow the operation. + */ + public void permits(CertConstraintParameters cp) + throws CertPathValidatorException { + if (!permitsImpl(cp.getCertificate().getPublicKey())) { + if (nextConstraint != null) { + nextConstraint.permits(cp); + return; + } + throw new CertPathValidatorException( + "Algorithm constraints check failed on keysize limits", + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + } + } + + // Check if key constraint disable the specified key + // Uses old style permit() + public boolean permits(Key key) { + // If we recursively find a constraint that permits us to use + // this key, return true and skip any other constraint checks. + if (nextConstraint != null && nextConstraint.permits(key)) { + return true; + } + if (debug != null) { + debug.println("KeySizeConstraints.permits(): " + algorithm); + } + + return permitsImpl(key); + } + + private boolean permitsImpl(Key key) { + // Verify this constraint is for this public key algorithm + if (algorithm.compareToIgnoreCase(key.getAlgorithm()) != 0) { + return true; + } + + int size = KeyUtil.getKeySize(key); if (size == 0) { - return true; // we don't allow any key of size 0. + return false; // we don't allow any key of size 0. } else if (size > 0) { - return ((size < minSize) || (size > maxSize) || + return !((size < minSize) || (size > maxSize) || (prohibitedSize == size)); } // Otherwise, the key size is not accessible. Conservatively, // please don't disable such keys. - return false; + return true; } } - } diff --git a/jdk/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java b/jdk/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java index d8803348a5d..7c8fe9af51d 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java +++ b/jdk/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,6 @@ package sun.security.util; import java.security.AlgorithmParameters; import java.security.CryptoPrimitive; import java.security.Key; -import java.util.HashMap; -import java.util.Map; import java.util.Set; import static sun.security.util.AbstractAlgorithmConstraints.getAlgorithms; @@ -42,15 +40,12 @@ public class LegacyAlgorithmConstraints extends AbstractAlgorithmConstraints { public static final String PROPERTY_TLS_LEGACY_ALGS = "jdk.tls.legacyAlgorithms"; - private static final Map legacyAlgorithmsMap = - new HashMap<>(); - private final String[] legacyAlgorithms; public LegacyAlgorithmConstraints(String propertyName, AlgorithmDecomposer decomposer) { super(decomposer); - legacyAlgorithms = getAlgorithms(legacyAlgorithmsMap, propertyName); + legacyAlgorithms = getAlgorithms(propertyName); } @Override diff --git a/jdk/src/java.base/share/classes/sun/security/x509/X509CertImpl.java b/jdk/src/java.base/share/classes/sun/security/x509/X509CertImpl.java index 0e4da831a83..8d496ad85c4 100644 --- a/jdk/src/java.base/share/classes/sun/security/x509/X509CertImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/x509/X509CertImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1924,17 +1924,18 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { public String getFingerprint(String algorithm) { return fingerprints.computeIfAbsent(algorithm, - x -> getCertificateFingerPrint(x)); + x -> getFingerprint(x, this)); } /** * Gets the requested finger print of the certificate. The result * only contains 0-9 and A-F. No small case, no colon. */ - private String getCertificateFingerPrint(String mdAlg) { + public static String getFingerprint(String algorithm, + X509Certificate cert) { try { - byte[] encCertInfo = getEncoded(); - MessageDigest md = MessageDigest.getInstance(mdAlg); + byte[] encCertInfo = cert.getEncoded(); + MessageDigest md = MessageDigest.getInstance(algorithm); byte[] digest = md.digest(encCertInfo); StringBuilder sb = new StringBuilder(digest.length * 2); for (int i = 0; i < digest.length; i++) { diff --git a/jdk/src/java.base/share/conf/security/java.security b/jdk/src/java.base/share/conf/security/java.security index 6a9803bf425..fa2da13c195 100644 --- a/jdk/src/java.base/share/conf/security/java.security +++ b/jdk/src/java.base/share/conf/security/java.security @@ -497,13 +497,13 @@ krb5.kdc.bad.policy = tryLast # " DisabledAlgorithm { , DisabledAlgorithm } " # # DisabledAlgorithm: -# AlgorithmName [Constraint] +# AlgorithmName [Constraint] { '&' Constraint } # # AlgorithmName: # (see below) # # Constraint: -# KeySizeConstraint +# KeySizeConstraint, CertConstraint # # KeySizeConstraint: # keySize Operator DecimalInteger @@ -520,6 +520,9 @@ krb5.kdc.bad.policy = tryLast # DecimalDigit: one of # 1 2 3 4 5 6 7 8 9 0 # +# CertConstraint +# jdkCA +# # The "AlgorithmName" is the standard algorithm name of the disabled # algorithm. See "Java Cryptography Architecture Standard Algorithm Name # Documentation" for information about Standard Algorithm Names. Matching @@ -542,6 +545,29 @@ krb5.kdc.bad.policy = tryLast # be disabled. Note that the "KeySizeConstraint" only makes sense to key # algorithms. # +# "CertConstraint" specifies additional constraints for +# certificates that contain algorithms that are restricted: +# +#   "jdkCA" prohibits the specified algorithm only if the algorithm is used +#     in a certificate chain that terminates at a marked trust anchor in the +#     lib/security/cacerts keystore.  All other chains are not affected. +#     If the jdkCA constraint is not set, then all chains using the +#     specified algorithm are restricted. jdkCA may only be used once in +# a DisabledAlgorithm expression. +#     Example:  To apply this constraint to SHA-1 certificates, include +#     the following:  "SHA1 jdkCA" +# +# When an algorithm must satisfy more than one constraint, it must be +# delimited by an ampersand '&'. For example, to restrict certificates in a +# chain that terminate at a distribution provided trust anchor and contain +# RSA keys that are less than or equal to 1024 bits, add the following +# constraint: "RSA keySize <= 1024 & jdkCA". +# +# All DisabledAlgorithms expressions are processed in the order defined in the +# property. This requires lower keysize constraints to be specified +# before larger keysize constraints of the same algorithm. For example: +# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048". +# # Note: This property is currently used by Oracle's PKIX implementation. It # is not guaranteed to be examined and used by other implementations. # diff --git a/jdk/test/sun/security/tools/jarsigner/Warning.java b/jdk/test/sun/security/tools/jarsigner/Warning.java index cd8607c8be0..70233634e0b 100644 --- a/jdk/test/sun/security/tools/jarsigner/Warning.java +++ b/jdk/test/sun/security/tools/jarsigner/Warning.java @@ -89,7 +89,7 @@ public class Warning { issueCert("c"); run("jarsigner", "a.jar c") .shouldContain("chain is not validated. " + - "Reason: algorithm constraints check failed"); + "Reason: Algorithm constraints check failed"); recreateJar(); From ae6a62a6c83f249eab34cad57167e6d601745375 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 2 May 2016 18:10:36 -0700 Subject: [PATCH 218/222] 8155516: Suppress warnings from uses of deprecated Class.newInstance langtools Reviewed-by: jjg --- .../share/classes/javax/tools/ToolProvider.java | 4 +++- .../tools/javac/processing/JavacProcessingEnvironment.java | 6 ++++-- .../share/classes/com/sun/tools/sjavac/options/Option.java | 3 ++- .../internal/doclets/toolkit/taglets/TagletManager.java | 1 + .../share/classes/jdk/javadoc/internal/tool/Start.java | 4 +++- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java b/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java index 1909ce4285c..f438198fa33 100644 --- a/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java +++ b/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java @@ -123,7 +123,9 @@ public class ToolProvider { private static T getSystemTool(Class clazz, String moduleName, String className) { if (useLegacy) { try { - return Class.forName(className, true, ClassLoader.getSystemClassLoader()).asSubclass(clazz).newInstance(); + @SuppressWarnings("deprecation") + T result = Class.forName(className, true, ClassLoader.getSystemClassLoader()).asSubclass(clazz).newInstance(); + return result; } catch (ReflectiveOperationException e) { throw new Error(e); } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 30da7072e54..817e5273f52 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -282,6 +282,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (options.isSet(XPRINT)) { try { + @SuppressWarnings("deprecation") Processor processor = PrintingProcessor.class.newInstance(); processorIterator = List.of(processor).iterator(); } catch (Throwable t) { @@ -549,8 +550,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea try { Class processorClass = processorCL.loadClass(processorName); ensureReadable(processorClass); - processor = - (Processor) (processorClass.newInstance()); + @SuppressWarnings("deprecation") + Object tmp = processorClass.newInstance(); + processor = (Processor) tmp; } catch (ClassNotFoundException cnfe) { log.error("proc.processor.not.found", processorName); return false; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java index d64d3182cc0..9533e98c191 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,6 +151,7 @@ public enum Option { // Construct transformer try { Class trCls = Class.forName(classname); + @SuppressWarnings("deprecation") Transformer transformer = (Transformer) trCls.newInstance(); transformer.setExtra(extra); helper.addTransformer(suffix, transformer); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java index ec809050f3c..1b96e61b134 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java @@ -246,6 +246,7 @@ public class TagletManager { } tagClassLoader = fileManager.getClassLoader(TAGLET_PATH); Class customTagClass = tagClassLoader.loadClass(classname); + @SuppressWarnings("deprecation") Object instance = customTagClass.newInstance(); Taglet newLegacy = new UserTaglet((jdk.javadoc.doclet.taglet.Taglet)instance); String tname = newLegacy.getName(); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java index d998e077663..2cca6849e26 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java @@ -270,7 +270,9 @@ public class Start extends ToolOption.Helper { initMessager(); messager.setLocale(locale); try { - doclet = (Doclet) docletClass.newInstance(); + @SuppressWarnings("deprecation") + Object o = docletClass.newInstance(); + doclet = (Doclet) o; } catch (InstantiationException | IllegalAccessException exc) { exc.printStackTrace(); if (!apiMode) { From 39846dcf8d30421bc1e1bca9b0c49a8d96dd5cd8 Mon Sep 17 00:00:00 2001 From: Alex Kashchenko Date: Tue, 3 May 2016 07:44:52 +0100 Subject: [PATCH 219/222] 8153925: (fs) WatchService hangs on GetOverlappedResult and locks directory (win) Co-authored-by: Thomas Mader Reviewed-by: alanb --- .../sun/nio/fs/WindowsWatchService.java | 26 ++++- .../file/WatchService/DeleteInterference.java | 102 ++++++++++++++++++ 2 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 jdk/test/java/nio/file/WatchService/DeleteInterference.java diff --git a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java index 63b2112aca1..00e68fb785b 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java +++ b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java @@ -113,6 +113,10 @@ class WindowsWatchService // completion key (used to map I/O completion to WatchKey) private int completionKey; + // flag indicates that ReadDirectoryChangesW failed + // and overlapped I/O operation wasn't started + private boolean errorStartingOverlapped; + WindowsWatchKey(Path dir, AbstractWatchService watcher, FileKey fileKey) @@ -175,6 +179,14 @@ class WindowsWatchService return completionKey; } + void setErrorStartingOverlapped(boolean value) { + errorStartingOverlapped = value; + } + + boolean isErrorStartingOverlapped() { + return errorStartingOverlapped; + } + // Invalidate the key, assumes that resources have been released void invalidate() { ((WindowsWatchService)watcher()).poller.releaseResources(this); @@ -182,6 +194,7 @@ class WindowsWatchService buffer = null; countAddress = 0; overlappedAddress = 0; + errorStartingOverlapped = false; } @Override @@ -455,11 +468,13 @@ class WindowsWatchService * resources. */ private void releaseResources(WindowsWatchKey key) { - try { - CancelIo(key.handle()); - GetOverlappedResult(key.handle(), key.overlappedAddress()); - } catch (WindowsException expected) { - // expected as I/O operation has been cancelled + if (!key.isErrorStartingOverlapped()) { + try { + CancelIo(key.handle()); + GetOverlappedResult(key.handle(), key.overlappedAddress()); + } catch (WindowsException expected) { + // expected as I/O operation has been cancelled + } } CloseHandle(key.handle()); closeAttachedEvent(key.overlappedAddress()); @@ -628,6 +643,7 @@ class WindowsWatchService } catch (WindowsException x) { // no choice but to cancel key criticalError = true; + key.setErrorStartingOverlapped(true); } } if (criticalError) { diff --git a/jdk/test/java/nio/file/WatchService/DeleteInterference.java b/jdk/test/java/nio/file/WatchService/DeleteInterference.java new file mode 100644 index 00000000000..6a11271a546 --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/DeleteInterference.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016, Red Hat, Inc. and/or its affiliates. + * 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. + */ + +/** + * @test + * @bug 8153925 + * @summary Tests potential interference between a thread creating and closing + * a WatchService with another thread that is deleting and re-creating the + * directory at around the same time. This scenario tickled a timing bug + * in the Windows implementation. + */ + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.WatchService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import static java.nio.file.StandardWatchEventKinds.*; + +public class DeleteInterference { + + private static final int ITERATIONS_COUNT = 1024; + + /** + * Execute two tasks in a thread pool. One task loops on creating and + * closing a WatchService, the other task deletes and re-creates the + * directory. + */ + public static void main(String[] args) throws Exception { + Path dir = Files.createTempDirectory("work"); + ExecutorService pool = Executors.newCachedThreadPool(); + try { + Future task1 = pool.submit(() -> openAndCloseWatcher(dir)); + Future task2 = pool.submit(() -> deleteAndRecreateDirectory(dir)); + task1.get(); + task2.get(); + } finally { + pool.shutdown(); + deleteFileTree(dir); + } + } + + private static void openAndCloseWatcher(Path dir) { + FileSystem fs = FileSystems.getDefault(); + for (int i = 0; i < ITERATIONS_COUNT; i++) { + try (WatchService watcher = fs.newWatchService()) { + dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + } catch (IOException ioe) { + // ignore + } + } + } + + private static void deleteAndRecreateDirectory(Path dir) { + for (int i = 0; i < ITERATIONS_COUNT; i++) { + try { + deleteFileTree(dir); + Path subdir = Files.createDirectories(dir.resolve("subdir")); + Files.createFile(subdir.resolve("test")); + } catch (IOException ioe) { + // ignore + } + } + } + + private static void deleteFileTree(Path file) { + try { + if (Files.isDirectory(file)) { + try (DirectoryStream stream = Files.newDirectoryStream(file)) { + for (Path pa : stream) { + deleteFileTree(pa); + } + } + } + Files.delete(file); + } catch (IOException ioe) { + // ignore + } + } +} From 3a647e6b88a3c4fb200b5ddafebfb2c6b52eb571 Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 21:36:12 +0200 Subject: [PATCH 220/222] Added tag jdk-9+115 for changeset 8d78fb40648d --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 0eced0f9e0d..3aec595d887 100644 --- a/.hgtags +++ b/.hgtags @@ -357,3 +357,4 @@ a6614ff7bf09da74be1d0ef3d9755090d244697a jdk-9+111 7359994942f8d8e723b584d66a3a92c2e9e95e5c jdk-9+112 6072af7a98be3922f26bdce71b53bb3646cb2ac9 jdk-9+113 c84d0cce090e161d736de69e941830adf8c2f87a jdk-9+114 +8d78fb40648dd221ce4ef19f9d5aa41ee1a3a884 jdk-9+115 From 1117b02a8eff96ef0ce97911c6f8b3b42e495ed3 Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 21:38:13 +0200 Subject: [PATCH 221/222] Added tag jdk-9+116 for changeset 84aba7335005 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 3aec595d887..f293837b51c 100644 --- a/.hgtags +++ b/.hgtags @@ -358,3 +358,4 @@ a6614ff7bf09da74be1d0ef3d9755090d244697a jdk-9+111 6072af7a98be3922f26bdce71b53bb3646cb2ac9 jdk-9+113 c84d0cce090e161d736de69e941830adf8c2f87a jdk-9+114 8d78fb40648dd221ce4ef19f9d5aa41ee1a3a884 jdk-9+115 +84aba7335005a3a47751dcf1f37935f97df9f99a jdk-9+116 From 4956880699c1947cab78e7b3db1f705e731815d3 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Fri, 29 Apr 2016 08:39:22 +0200 Subject: [PATCH 222/222] 8155245: Add logging when MMU target is violated Reviewed-by: ehelin, mgerdin --- hotspot/src/share/vm/gc/g1/g1MMUTracker.cpp | 5 +++++ hotspot/src/share/vm/logging/logPrefix.hpp | 1 + hotspot/src/share/vm/logging/logTag.hpp | 1 + 3 files changed, 7 insertions(+) diff --git a/hotspot/src/share/vm/gc/g1/g1MMUTracker.cpp b/hotspot/src/share/vm/gc/g1/g1MMUTracker.cpp index e8c7a4e9f9b..fdb99afe7b7 100644 --- a/hotspot/src/share/vm/gc/g1/g1MMUTracker.cpp +++ b/hotspot/src/share/vm/gc/g1/g1MMUTracker.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/g1/g1MMUTracker.hpp" #include "gc/shared/gcTrace.hpp" +#include "logging/log.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/ostream.hpp" @@ -107,6 +108,10 @@ void G1MMUTrackerQueue::add_pause(double start, double end) { // Current entry needs to be added before calculating the value double slice_time = calculate_gc_time(end); G1MMUTracer::report_mmu(_time_slice, slice_time, _max_gc_time); + + if (slice_time >= _max_gc_time) { + log_info(gc, mmu)("MMU target violated: %.1lfms (%.1lfms/%.1lfms)", slice_time * 1000.0, _max_gc_time * 1000.0, _time_slice * 1000); + } } // basically the _internal call does not remove expired entries diff --git a/hotspot/src/share/vm/logging/logPrefix.hpp b/hotspot/src/share/vm/logging/logPrefix.hpp index 8d2ae12adf3..7e4da0f058e 100644 --- a/hotspot/src/share/vm/logging/logPrefix.hpp +++ b/hotspot/src/share/vm/logging/logPrefix.hpp @@ -64,6 +64,7 @@ DEBUG_ONLY(size_t Test_log_prefix_prefixer(char* buf, size_t len);) LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, liveness)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, marking)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, metaspace)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, mmu)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, start)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, task)) \ diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index d9759dca859..1f0a1c31e2c 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -67,6 +67,7 @@ LOG_TAG(logging) \ LOG_TAG(marking) \ LOG_TAG(metaspace) \ + LOG_TAG(mmu) \ LOG_TAG(modules) \ LOG_TAG(monitorinflation) \ LOG_TAG(monitormismatch) \