diff --git a/make/java/java/mapfile-vers b/make/java/java/mapfile-vers index 60f0f8646079725a6ae0771f73c2172d131bacd1..dc20bed7b9e5cafa736797d1d87b1280673d59c2 100644 --- a/make/java/java/mapfile-vers +++ b/make/java/java/mapfile-vers @@ -217,7 +217,7 @@ SUNWprivate_1.1 { Java_java_lang_Throwable_fillInStackTrace; Java_java_lang_Throwable_getStackTraceDepth; Java_java_lang_Throwable_getStackTraceElement; - Java_java_lang_UNIXProcess_initIDs; + Java_java_lang_UNIXProcess_init; Java_java_lang_UNIXProcess_waitForProcessExit; Java_java_lang_UNIXProcess_forkAndExec; Java_java_lang_UNIXProcess_destroyProcess; diff --git a/makefiles/mapfiles/libjava/mapfile-vers b/makefiles/mapfiles/libjava/mapfile-vers index 60f0f8646079725a6ae0771f73c2172d131bacd1..dc20bed7b9e5cafa736797d1d87b1280673d59c2 100644 --- a/makefiles/mapfiles/libjava/mapfile-vers +++ b/makefiles/mapfiles/libjava/mapfile-vers @@ -217,7 +217,7 @@ SUNWprivate_1.1 { Java_java_lang_Throwable_fillInStackTrace; Java_java_lang_Throwable_getStackTraceDepth; Java_java_lang_Throwable_getStackTraceElement; - Java_java_lang_UNIXProcess_initIDs; + Java_java_lang_UNIXProcess_init; Java_java_lang_UNIXProcess_waitForProcessExit; Java_java_lang_UNIXProcess_forkAndExec; Java_java_lang_UNIXProcess_destroyProcess; diff --git a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 9134bcf22eae294c2b9342b23451f1396e1819ed..16703fc09177dfd3dc1bb2876f4a5fb0ee8c9ec0 100644 --- a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -184,7 +184,7 @@ import java.security.PrivilegedAction; for (int i=0; i { /** - * The value since the epoch; can be negative. - */ - private final long value; - - /** - * The unit of granularity to interpret the value. + * The unit of granularity to interpret the value. Null if + * this {@code FileTime} is converted from an {@code Instant}, + * the {@code value} and {@code unit} pair will not be used + * in this scenario. */ private final TimeUnit unit; /** - * The value return by toString (created lazily) + * The value since the epoch; can be negative. */ - private String valueAsString; + private final long value; /** - * The value in days and excess nanos (created lazily) + * The value as Instant (created lazily, if not from an instant) */ - private DaysAndNanos daysAndNanos; + private Instant instant; /** - * Returns a DaysAndNanos object representing the value. + * The value return by toString (created lazily) */ - private DaysAndNanos asDaysAndNanos() { - if (daysAndNanos == null) - daysAndNanos = new DaysAndNanos(value, unit); - return daysAndNanos; - } + private String valueAsString; /** * Initializes a new instance of this class. */ - private FileTime(long value, TimeUnit unit) { - if (unit == null) - throw new NullPointerException(); + private FileTime(long value, TimeUnit unit, Instant instant) { this.value = value; this.unit = unit; + this.instant = instant; } /** @@ -102,7 +93,8 @@ public final class FileTime * @return a {@code FileTime} representing the given value */ public static FileTime from(long value, TimeUnit unit) { - return new FileTime(value, unit); + Objects.requireNonNull(unit, "unit"); + return new FileTime(value, unit, null); } /** @@ -115,7 +107,22 @@ public final class FileTime * @return a {@code FileTime} representing the given value */ public static FileTime fromMillis(long value) { - return new FileTime(value, TimeUnit.MILLISECONDS); + return new FileTime(value, TimeUnit.MILLISECONDS, null); + } + + /** + * Returns a {@code FileTime} representing the same point of time value + * on the time-line as the provided {@code Instant} object. + * + * @param instant + * the instant to convert + * @return a {@code FileTime} representing the same point on the time-line + * as the provided instant + * @since 1.8 + */ + public static FileTime from(Instant instant) { + Objects.requireNonNull(instant, "instant"); + return new FileTime(0, null, instant); } /** @@ -132,7 +139,22 @@ public final class FileTime * since the epoch (1970-01-01T00:00:00Z); can be negative */ public long to(TimeUnit unit) { - return unit.convert(this.value, this.unit); + Objects.requireNonNull(unit, "unit"); + if (this.unit != null) { + return unit.convert(this.value, this.unit); + } else { + long secs = unit.convert(instant.getEpochSecond(), TimeUnit.SECONDS); + if (secs == Long.MIN_VALUE || secs == Long.MAX_VALUE) { + return secs; + } + long nanos = unit.convert(instant.getNano(), TimeUnit.NANOSECONDS); + long r = secs + nanos; + // Math.addExact() variant + if (((secs ^ r) & (nanos ^ r)) < 0) { + return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE; + } + return r; + } } /** @@ -145,7 +167,110 @@ public final class FileTime * @return the value in milliseconds, since the epoch (1970-01-01T00:00:00Z) */ public long toMillis() { - return unit.toMillis(value); + if (unit != null) { + return unit.toMillis(value); + } else { + long secs = instant.getEpochSecond(); + int nanos = instant.getNano(); + // Math.multiplyExact() variant + long r = secs * 1000; + long ax = Math.abs(secs); + if (((ax | 1000) >>> 31 != 0)) { + if ((r / 1000) != secs) { + return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE; + } + } + return r + nanos / 1000_000; + } + } + + /** + * Time unit constants for conversion. + */ + private static final long HOURS_PER_DAY = 24L; + private static final long MINUTES_PER_HOUR = 60L; + private static final long SECONDS_PER_MINUTE = 60L; + private static final long SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR; + private static final long SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; + private static final long MILLIS_PER_SECOND = 1000L; + private static final long MICROS_PER_SECOND = 1000_000L; + private static final long NANOS_PER_SECOND = 1000_000_000L; + private static final int NANOS_PER_MILLI = 1000_000; + private static final int NANOS_PER_MICRO = 1000; + // The epoch second of Instant.MIN. + private static final long MIN_SECOND = -31557014167219200L; + // The epoch second of Instant.MAX. + private static final long MAX_SECOND = 31556889864403199L; + + /* + * Scale d by m, checking for overflow. + */ + private static long scale(long d, long m, long over) { + if (d > over) return Long.MAX_VALUE; + if (d < -over) return Long.MIN_VALUE; + return d * m; + } + + /** + * Converts this {@code FileTime} object to an {@code Instant}. + * + *

The conversion creates an {@code Instant} that represents the + * same point on the time-line as this {@code FileTime}. + * + *

{@code FileTime} can store points on the time-line further in the + * future and further in the past than {@code Instant}. Conversion + * from such further time points saturates to {@link Instant.MIN} if + * earlier than {@code Instant.MIN} or {@link Instant.MAX} if later + * than {@code Instant.MAX}. + * + * @return an instant representing the same point on the time-line as + * this {@code FileTime} object + * @since 1.8 + */ + public Instant toInstant() { + if (instant == null) { + long secs = 0L; + int nanos = 0; + switch (unit) { + case DAYS: + secs = scale(value, SECONDS_PER_DAY, + Long.MAX_VALUE/SECONDS_PER_DAY); + break; + case HOURS: + secs = scale(value, SECONDS_PER_HOUR, + Long.MAX_VALUE/SECONDS_PER_HOUR); + break; + case MINUTES: + secs = scale(value, SECONDS_PER_MINUTE, + Long.MAX_VALUE/SECONDS_PER_MINUTE); + break; + case SECONDS: + secs = value; + break; + case MILLISECONDS: + secs = Math.floorDiv(value, MILLIS_PER_SECOND); + nanos = (int)Math.floorMod(value, MILLIS_PER_SECOND) + * NANOS_PER_MILLI; + break; + case MICROSECONDS: + secs = Math.floorDiv(value, MICROS_PER_SECOND); + nanos = (int)Math.floorMod(value, MICROS_PER_SECOND) + * NANOS_PER_MICRO; + break; + case NANOSECONDS: + secs = Math.floorDiv(value, NANOS_PER_SECOND); + nanos = (int)Math.floorMod(value, NANOS_PER_SECOND); + break; + default : throw new AssertionError("Unit not handled"); + } + if (secs <= MIN_SECOND) + instant = Instant.MIN; + else if (secs >= MAX_SECOND) + instant = Instant.MAX; + else + instant = Instant.ofEpochSecond(secs, nanos); + } + return instant; } /** @@ -176,8 +301,25 @@ public final class FileTime */ @Override public int hashCode() { - // hashcode of days/nanos representation to satisfy contract with equals - return asDaysAndNanos().hashCode(); + // hashcode of instant representation to satisfy contract with equals + return toInstant().hashCode(); + } + + private long toDays() { + if (unit != null) { + return unit.toDays(value); + } else { + return TimeUnit.SECONDS.toDays(toInstant().getEpochSecond()); + } + } + + private long toExcessNanos(long days) { + if (unit != null) { + return unit.toNanos(value - unit.convert(days, TimeUnit.DAYS)); + } else { + return TimeUnit.SECONDS.toNanos(toInstant().getEpochSecond() + - TimeUnit.DAYS.toSeconds(days)); + } } /** @@ -194,14 +336,52 @@ public final class FileTime @Override public int compareTo(FileTime other) { // same granularity - if (unit == other.unit) { - return (value < other.value) ? -1 : (value == other.value ? 0 : 1); + if (unit != null && unit == other.unit) { + return Long.compare(value, other.value); } else { - // compare using days/nanos representation when unit differs - return asDaysAndNanos().compareTo(other.asDaysAndNanos()); + // compare using instant representation when unit differs + long secs = toInstant().getEpochSecond(); + long secsOther = other.toInstant().getEpochSecond(); + int cmp = Long.compare(secs, secsOther); + if (cmp != 0) { + return cmp; + } + cmp = Long.compare(toInstant().getNano(), other.toInstant().getNano()); + if (cmp != 0) { + return cmp; + } + if (secs != MAX_SECOND && secs != MIN_SECOND) { + return 0; + } + // if both this and other's Instant reps are MIN/MAX, + // use daysSinceEpoch and nanosOfDays, which will not + // saturate during calculation. + long days = toDays(); + long daysOther = other.toDays(); + if (days == daysOther) { + return Long.compare(toExcessNanos(days), other.toExcessNanos(daysOther)); + } + return Long.compare(days, daysOther); } } + // days in a 400 year cycle = 146097 + // days in a 10,000 year cycle = 146097 * 25 + // seconds per day = 86400 + private static final long DAYS_PER_10000_YEARS = 146097L * 25L; + private static final long SECONDS_PER_10000_YEARS = 146097L * 25L * 86400L; + private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L; + + // append year/month/day/hour/minute/second/nano with width and 0 padding + private StringBuilder append(StringBuilder sb, int w, int d) { + while (w > 0) { + sb.append((char)(d/w + '0')); + d = d % w; + w /= 10; + } + return sb; + } + /** * Returns the string representation of this {@code FileTime}. The string * is returned in the 0) { - sb.append('0'); - } - if (s.charAt(len-1) == '0') { - // drop trailing zeros - len--; - while (s.charAt(len-1) == '0') - len--; - sb.append(s.substring(0, len)); - } else { - sb.append(s); - } - fractionAsString = sb.toString(); - } + if (valueAsString == null) { + long secs = 0L; + int nanos = 0; + if (instant == null && unit.compareTo(TimeUnit.SECONDS) >= 0) { + secs = unit.toSeconds(value); + } else { + secs = toInstant().getEpochSecond(); + nanos = toInstant().getNano(); } - - // create calendar to use with formatter. - GregorianCalendar cal = - new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.ROOT); - if (value < 0L) - cal.setGregorianChange(new Date(Long.MIN_VALUE)); - cal.setTimeInMillis(ms); - - // years are negative before common era - String sign = (cal.get(Calendar.ERA) == GregorianCalendar.BC) ? "-" : ""; - - // [-]YYYY-MM-DDThh:mm:ss[.s]Z - v = new Formatter(Locale.ROOT) - .format("%s%tFT%tR:%tS%sZ", sign, cal, cal, cal, fractionAsString) - .toString(); - valueAsString = v; - } - return v; - } - - /** - * Represents a FileTime's value as two longs: the number of days since - * the epoch, and the excess (in nanoseconds). This is used for comparing - * values with different units of granularity. - */ - private static class DaysAndNanos implements Comparable { - // constants for conversion - private static final long C0 = 1L; - private static final long C1 = C0 * 24L; - private static final long C2 = C1 * 60L; - private static final long C3 = C2 * 60L; - private static final long C4 = C3 * 1000L; - private static final long C5 = C4 * 1000L; - private static final long C6 = C5 * 1000L; - - /** - * The value (in days) since the epoch; can be negative. - */ - private final long days; - - /** - * The excess (in nanoseconds); can be negative if days <= 0. - */ - private final long excessNanos; - - /** - * Initializes a new instance of this class. - */ - DaysAndNanos(long value, TimeUnit unit) { - long scale; - switch (unit) { - case DAYS : scale = C0; break; - case HOURS : scale = C1; break; - case MINUTES : scale = C2; break; - case SECONDS : scale = C3; break; - case MILLISECONDS : scale = C4; break; - case MICROSECONDS : scale = C5; break; - case NANOSECONDS : scale = C6; break; - default : throw new AssertionError("Unit not handled"); + LocalDateTime ldt; + int year = 0; + if (secs >= -SECONDS_0000_TO_1970) { + // current era + long zeroSecs = secs - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970; + long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1; + long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS); + ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC); + year = ldt.getYear() + (int)hi * 10000; + } else { + // before current era + long zeroSecs = secs + SECONDS_0000_TO_1970; + long hi = zeroSecs / SECONDS_PER_10000_YEARS; + long lo = zeroSecs % SECONDS_PER_10000_YEARS; + ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC); + year = ldt.getYear() + (int)hi * 10000; } - this.days = unit.toDays(value); - this.excessNanos = unit.toNanos(value - (this.days * scale)); - } - - /** - * Returns the fraction of a second, in nanoseconds. - */ - long fractionOfSecondInNanos() { - return excessNanos % (1000L * 1000L * 1000L); - } - - @Override - public boolean equals(Object obj) { - return (obj instanceof DaysAndNanos) ? - compareTo((DaysAndNanos)obj) == 0 : false; - } - - @Override - public int hashCode() { - return (int)(days ^ (days >>> 32) ^ - excessNanos ^ (excessNanos >>> 32)); - } - - @Override - public int compareTo(DaysAndNanos other) { - if (this.days != other.days) - return (this.days < other.days) ? -1 : 1; - return (this.excessNanos < other.excessNanos) ? -1 : - (this.excessNanos == other.excessNanos) ? 0 : 1; + if (year <= 0) { + year = year - 1; + } + int fraction = ldt.getNano(); + StringBuilder sb = new StringBuilder(64); + sb.append(year < 0 ? "-" : ""); + year = Math.abs(year); + if (year < 10000) { + append(sb, 1000, Math.abs(year)); + } else { + sb.append(String.valueOf(year)); + } + sb.append('-'); + append(sb, 10, ldt.getMonthValue()); + sb.append('-'); + append(sb, 10, ldt.getDayOfMonth()); + sb.append('T'); + append(sb, 10, ldt.getHour()); + sb.append(':'); + append(sb, 10, ldt.getMinute()); + sb.append(':'); + append(sb, 10, ldt.getSecond()); + if (fraction != 0) { + sb.append('.'); + // adding leading zeros and stripping any trailing zeros + int w = 100_000_000; + while (fraction % 10 == 0) { + fraction /= 10; + w /= 10; + } + append(sb, w, fraction); + } + sb.append('Z'); + valueAsString = sb.toString(); } + return valueAsString; } } diff --git a/src/share/classes/java/util/ArrayList.java b/src/share/classes/java/util/ArrayList.java index 42a97e70f044601b0386f9858285d44083157e06..46bd55760a7161e8cebc417e432a75727d2bcd51 100644 --- a/src/share/classes/java/util/ArrayList.java +++ b/src/share/classes/java/util/ArrayList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,9 +104,21 @@ public class ArrayList extends AbstractList { private static final long serialVersionUID = 8683452581122892189L; + /** + * Default initial capacity. + */ + private static final int DEFAULT_CAPACITY = 10; + + /** + * Shared empty array instance used for empty instances. + */ + private static final Object[] EMPTY_ELEMENTDATA = {}; + /** * The array buffer into which the elements of the ArrayList are stored. - * The capacity of the ArrayList is the length of this array buffer. + * The capacity of the ArrayList is the length of this array buffer. Any + * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to + * DEFAULT_CAPACITY when the first element is added. */ private transient Object[] elementData; @@ -136,7 +148,8 @@ public class ArrayList extends AbstractList * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { - this(10); + super(); + this.elementData = EMPTY_ELEMENTDATA; } /** @@ -162,8 +175,7 @@ public class ArrayList extends AbstractList */ public void trimToSize() { modCount++; - int oldCapacity = elementData.length; - if (size < oldCapacity) { + if (size < elementData.length) { elementData = Arrays.copyOf(elementData, size); } } @@ -176,12 +188,29 @@ public class ArrayList extends AbstractList * @param minCapacity the desired minimum capacity */ public void ensureCapacity(int minCapacity) { - if (minCapacity > 0) - ensureCapacityInternal(minCapacity); + int minExpand = (elementData != EMPTY_ELEMENTDATA) + // any size if real element table + ? 0 + // larger than default for empty table. It's already supposed to be + // at default size. + : DEFAULT_CAPACITY; + + if (minCapacity > minExpand) { + ensureExplicitCapacity(minCapacity); + } } private void ensureCapacityInternal(int minCapacity) { + if (elementData == EMPTY_ELEMENTDATA) { + minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); + } + + ensureExplicitCapacity(minCapacity); + } + + private void ensureExplicitCapacity(int minCapacity) { modCount++; + // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); @@ -450,7 +479,7 @@ public class ArrayList extends AbstractList if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); - elementData[--size] = null; // Let gc do its work + elementData[--size] = null; // clear to let GC do its work return oldValue; } @@ -495,7 +524,7 @@ public class ArrayList extends AbstractList if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); - elementData[--size] = null; // Let gc do its work + elementData[--size] = null; // clear to let GC do its work } /** @@ -505,7 +534,7 @@ public class ArrayList extends AbstractList public void clear() { modCount++; - // Let gc do its work + // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; @@ -586,10 +615,12 @@ public class ArrayList extends AbstractList System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); - // Let gc do its work + // clear to let GC do its work int newSize = size - (toIndex-fromIndex); - while (size != newSize) - elementData[--size] = null; + for (int i = newSize; i < size; i++) { + elementData[i] = null; + } + size = newSize; } /** @@ -677,6 +708,7 @@ public class ArrayList extends AbstractList w += size - r; } if (w != size) { + // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; @@ -701,17 +733,17 @@ public class ArrayList extends AbstractList int expectedModCount = modCount; s.defaultWriteObject(); - // Write out array length - s.writeInt(elementData.length); + // Write out size as capacity for behavioural compatibility with clone() + s.writeInt(size); // Write out all elements in the proper order. - for (int i=0; i extends AbstractList */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + elementData = EMPTY_ELEMENTDATA; + // Read in size, and any hidden stuff s.defaultReadObject(); - // Read in array length and allocate array - int arrayLength = s.readInt(); - Object[] a = elementData = new Object[arrayLength]; + // Read in capacity + s.readInt(); // ignored + + if (size > 0) { + // be like clone(), allocate array based upon size not capacity + ensureCapacityInternal(size); - // Read in all elements in the proper order. - for (int i=0; i BinaryOperator lesserOf(Comparator comparator) { + Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; } @@ -274,6 +275,7 @@ public class Comparators { * according to the supplied {@code Comparator} */ public static BinaryOperator greaterOf(Comparator comparator) { + Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; } } diff --git a/src/share/classes/java/util/HashMap.java b/src/share/classes/java/util/HashMap.java index 9990a6ef68c188b257d40791c87f388b02e96f25..d1ac0cf16fe4ebf99738edcf05ebe7b71d37041e 100644 --- a/src/share/classes/java/util/HashMap.java +++ b/src/share/classes/java/util/HashMap.java @@ -129,7 +129,7 @@ public class HashMap /** * The default initial capacity - MUST be a power of two. */ - static final int DEFAULT_INITIAL_CAPACITY = 16; + static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 /** * The maximum capacity, used if a higher value is implicitly specified @@ -143,10 +143,15 @@ public class HashMap */ static final float DEFAULT_LOAD_FACTOR = 0.75f; + /** + * An empty table instance to share when the table is not inflated. + */ + static final Entry[] EMPTY_TABLE = {}; + /** * The table, resized as necessary. Length MUST Always be a power of two. */ - transient Entry[] table; + transient Entry[] table = EMPTY_TABLE; /** * The number of key-value mappings contained in this map. @@ -157,6 +162,8 @@ public class HashMap * The next size value at which to resize (capacity * load factor). * @serial */ + // If table == EMPTY_TABLE then this is the initial capacity at which the + // table will be created when inflated. int threshold; /** @@ -223,14 +230,8 @@ public class HashMap throw new IllegalArgumentException("Illegal load factor: " + loadFactor); - // Find a power of 2 >= initialCapacity - int capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; - this.loadFactor = loadFactor; - threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); - table = new Entry[capacity]; + threshold = initialCapacity; init(); } @@ -265,9 +266,33 @@ public class HashMap public HashMap(Map m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); + inflateTable(threshold); + putAllForCreate(m); } + private static int roundUpToPowerOf2(int number) { + // assert number >= 0 : "number must be non-negative"; + int rounded = number >= MAXIMUM_CAPACITY + ? MAXIMUM_CAPACITY + : (rounded = Integer.highestOneBit(number)) != 0 + ? (Integer.bitCount(number) > 1) ? rounded << 1 : rounded + : 1; + + return rounded; + } + + /** + * Inflates the table. + */ + private void inflateTable(int toSize) { + // Find a power of 2 >= toSize + int capacity = roundUpToPowerOf2(toSize); + + threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); + table = new Entry[capacity]; + } + // internal utilities /** @@ -305,6 +330,7 @@ public class HashMap * Returns index for hash code h. */ static int indexFor(int h, int length) { + // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2"; return h & (length-1); } @@ -369,6 +395,10 @@ public class HashMap */ @SuppressWarnings("unchecked") final Entry getEntry(Object key) { + if (isEmpty()) { + return null; + } + int hash = (key == null) ? 0 : hash(key); for (Entry e = table[indexFor(hash, table.length)]; e != null; @@ -381,7 +411,6 @@ public class HashMap return null; } - /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old @@ -395,6 +424,9 @@ public class HashMap * previously associated null with key.) */ public V put(K key, V value) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } if (key == null) return putForNullKey(value); int hash = hash(key); @@ -529,6 +561,10 @@ public class HashMap if (numKeysToBeAdded == 0) return; + if (table == EMPTY_TABLE) { + inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold)); + } + /* * Expand the map if the map if the number of mappings to be added * is greater than or equal to threshold. This is conservative; the @@ -573,6 +609,9 @@ public class HashMap * for this key. */ final Entry removeEntryForKey(Object key) { + if (isEmpty()) { + return null; + } int hash = (key == null) ? 0 : hash(key); int i = indexFor(hash, table.length); @SuppressWarnings("unchecked") @@ -605,7 +644,7 @@ public class HashMap * for matching. */ final Entry removeMapping(Object o) { - if (!(o instanceof Map.Entry)) + if (isEmpty() || !(o instanceof Map.Entry)) return null; Map.Entry entry = (Map.Entry) o; @@ -641,9 +680,7 @@ public class HashMap */ public void clear() { modCount++; - Entry[] tab = table; - for (int i = 0; i < tab.length; i++) - tab[i] = null; + Arrays.fill(table, null); size = 0; } @@ -693,7 +730,14 @@ public class HashMap } catch (CloneNotSupportedException e) { // assert false; } - result.table = new Entry[table.length]; + if (result.table != EMPTY_TABLE) { + result.inflateTable(Math.min( + (int) Math.min( + size * Math.min(1 / loadFactor, 4.0f), + // we have limits... + HashMap.MAXIMUM_CAPACITY), + table.length)); + } result.entrySet = null; result.modCount = 0; result.size = 0; @@ -749,8 +793,7 @@ public class HashMap } public final int hashCode() { - return (key==null ? 0 : key.hashCode()) ^ - (value==null ? 0 : value.hashCode()); + return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue()); } public final String toString() { @@ -1017,14 +1060,15 @@ public class HashMap private void writeObject(java.io.ObjectOutputStream s) throws IOException { - Iterator> i = - (size > 0) ? entrySet0().iterator() : null; - // Write out the threshold, loadfactor, and any hidden stuff s.defaultWriteObject(); // Write out number of buckets - s.writeInt(table.length); + if (table==EMPTY_TABLE) { + s.writeInt(roundUpToPowerOf2(threshold)); + } else { + s.writeInt(table.length); + } // Write out size (number of Mappings) s.writeInt(size); @@ -1049,16 +1093,18 @@ public class HashMap { // Read in the threshold (ignored), loadfactor, and any hidden stuff s.defaultReadObject(); - if (loadFactor <= 0 || Float.isNaN(loadFactor)) + if (loadFactor <= 0 || Float.isNaN(loadFactor)) { throw new InvalidObjectException("Illegal load factor: " + loadFactor); + } - // set hashMask + // set other fields that need values Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET, sun.misc.Hashing.randomHashSeed(this)); + table = EMPTY_TABLE; - // Read in number of buckets and allocate the bucket array; - s.readInt(); // ignored + // Read in number of buckets + s.readInt(); // ignored. // Read number of mappings int mappings = s.readInt(); @@ -1066,23 +1112,21 @@ public class HashMap throw new InvalidObjectException("Illegal mappings count: " + mappings); - int initialCapacity = (int) Math.min( - // capacity chosen by number of mappings - // and desired load (if >= 0.25) - mappings * Math.min(1 / loadFactor, 4.0f), - // we have limits... - HashMap.MAXIMUM_CAPACITY); - int capacity = 1; - // find smallest power of two which holds all mappings - while (capacity < initialCapacity) { - capacity <<= 1; + // capacity chosen by number of mappings and desired load (if >= 0.25) + int capacity = (int) Math.min( + mappings * Math.min(1 / loadFactor, 4.0f), + // we have limits... + HashMap.MAXIMUM_CAPACITY); + + // allocate the bucket array; + if (mappings > 0) { + inflateTable(capacity); + } else { + threshold = capacity; } - table = new Entry[capacity]; - threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); init(); // Give subclass a chance to do its thing. - // Read the keys and values, and put the mappings in the HashMap for (int i=0; iUnlike the method {@link requireNonNull(Object, String}, + * this method allows creation of the message to be deferred until + * after the null check is made. While this may confer a + * performance advantage in the non-null case, when deciding to + * call this method care should be taken that the costs of + * creating the message supplier are less than the cost of just + * creating the string message directly. + * + * @param obj the object reference to check for nullity + * @param messageSupplier supplier of the detail message to be + * used in the event that a {@code NullPointerException} is thrown + * @param the type of the reference + * @return {@code obj} if not {@code null} + * @throws NullPointerException if {@code obj} is {@code null} + * @since 1.8 + */ + public static T requireNonNull(T obj, Supplier messageSupplier) { + if (obj == null) + throw new NullPointerException(messageSupplier.get()); + return obj; + } } diff --git a/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java index 268a30cad8095024fe9a996c57347976902e0012..b872a59b50155aad82bd7eae555313fed6528192 100644 --- a/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java @@ -466,7 +466,10 @@ public class ZipFileSystem extends FileSystem { if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH) { u.type = eSrc.type; // make it the same type - if (!deletesrc) { // if it's not "rename", just take the data + if (deletesrc) { // if it's a "rename", take the data + u.bytes = eSrc.bytes; + u.file = eSrc.file; + } else { // if it's not "rename", copy the data if (eSrc.bytes != null) u.bytes = Arrays.copyOf(eSrc.bytes, eSrc.bytes.length); else if (eSrc.file != null) { @@ -1118,7 +1121,7 @@ public class ZipFileSystem extends FileSystem { if (old != null) { removeFromTree(old); } - if (e.type == Entry.NEW || e.type == Entry.FILECH) { + if (e.type == Entry.NEW || e.type == Entry.FILECH || e.type == Entry.COPY) { IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(e.name))); e.sibling = parent.child; parent.child = e; @@ -2326,12 +2329,12 @@ public class ZipFileSystem extends FileSystem { private void removeFromTree(IndexNode inode) { IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(inode.name))); IndexNode child = parent.child; - if (child == inode) { + if (child.equals(inode)) { parent.child = child.sibling; } else { IndexNode last = child; while ((child = child.sibling) != null) { - if (child == inode) { + if (child.equals(inode)) { last.sibling = child.sibling; break; } else { diff --git a/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h b/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h index 5085028c2239c8c34e51897c338a3ed3cf14d169..6391354a3c4bd6e94e842aeba4696e71b9dc454f 100644 --- a/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h +++ b/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h @@ -143,9 +143,9 @@ typedef struct _SurfaceType { * structure from the information present in a given Java Composite * object. */ -typedef JNIEXPORT void (JNICALL CompInfoFunc)(JNIEnv *env, - CompositeInfo *pCompInfo, - jobject Composite); +typedef void (JNICALL CompInfoFunc)(JNIEnv *env, + CompositeInfo *pCompInfo, + jobject Composite); /* * The additional information needed to implement a primitive that diff --git a/src/share/npt/npt.h b/src/share/npt/npt.h index c9cd9a3d20904b2c79eaa3a312501be36975ce0d..4f2a5620da57c161e6ecf23472072608c58deffc 100644 --- a/src/share/npt/npt.h +++ b/src/share/npt/npt.h @@ -94,13 +94,13 @@ typedef struct { JNIEXPORT void JNICALL nptInitialize (NptEnv **pnpt, char *nptVersion, char *options); -typedef JNIEXPORT void (JNICALL *NptInitialize) - (NptEnv **pnpt, char *nptVersion, char *options); +typedef void (JNICALL *NptInitialize) + (NptEnv **pnpt, char *nptVersion, char *options); JNIEXPORT void JNICALL nptTerminate (NptEnv* npt, char *options); -typedef JNIEXPORT void (JNICALL *NptTerminate) - (NptEnv* npt, char *options); +typedef void (JNICALL *NptTerminate) + (NptEnv* npt, char *options); #ifdef __cplusplus } /* extern "C" */ diff --git a/src/solaris/classes/java/lang/UNIXProcess.java.bsd b/src/solaris/classes/java/lang/UNIXProcess.java.bsd index d70c120267a8ddd8cb87a639b374bf79f3b41caa..f30ef34de4e9adddbae9b11b2bc7a35a5fd6a337 100644 --- a/src/solaris/classes/java/lang/UNIXProcess.java.bsd +++ b/src/solaris/classes/java/lang/UNIXProcess.java.bsd @@ -270,11 +270,10 @@ final class UNIXProcess extends Process { return !hasExited; } - /* This routine initializes JNI field offsets for the class */ - private static native void initIDs(); + private static native void init(); static { - initIDs(); + init(); } /** diff --git a/src/solaris/classes/java/lang/UNIXProcess.java.linux b/src/solaris/classes/java/lang/UNIXProcess.java.linux index 760ffa7b394e46144285c7026f31a13fd18f6243..9da9cb5125c594de8849bfce438c28bc0294e082 100644 --- a/src/solaris/classes/java/lang/UNIXProcess.java.linux +++ b/src/solaris/classes/java/lang/UNIXProcess.java.linux @@ -270,11 +270,10 @@ final class UNIXProcess extends Process { return !hasExited; } - /* This routine initializes JNI field offsets for the class */ - private static native void initIDs(); + private static native void init(); static { - initIDs(); + init(); } /** diff --git a/src/solaris/classes/java/lang/UNIXProcess.java.solaris b/src/solaris/classes/java/lang/UNIXProcess.java.solaris index ecdc280a08ffdf90fded204fd6a58493a7ed81a9..a7de626fb9e13b00e6360e6ba328c4a93dd8aebf 100644 --- a/src/solaris/classes/java/lang/UNIXProcess.java.solaris +++ b/src/solaris/classes/java/lang/UNIXProcess.java.solaris @@ -328,10 +328,9 @@ final class UNIXProcess extends Process { } - /* This routine initializes JNI field offsets for the class */ - private static native void initIDs(); + private static native void init(); static { - initIDs(); + init(); } } diff --git a/src/solaris/javavm/export/jni_md.h b/src/solaris/javavm/export/jni_md.h index baab364c9162433e024719c1b0e7aa9e8e8a93ca..0f3d1ed8b0cebbec392c897269ee2a48ef158568 100644 --- a/src/solaris/javavm/export/jni_md.h +++ b/src/solaris/javavm/export/jni_md.h @@ -26,8 +26,17 @@ #ifndef _JAVASOFT_JNI_MD_H_ #define _JAVASOFT_JNI_MD_H_ -#define JNIEXPORT -#define JNIIMPORT +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #define JNIEXPORT __attribute__((visibility("default"))) + #define JNIIMPORT __attribute__((visibility("default"))) +#else + #define JNIEXPORT + #define JNIIMPORT +#endif + #define JNICALL typedef int jint; diff --git a/src/solaris/native/java/lang/ProcessEnvironment_md.c b/src/solaris/native/java/lang/ProcessEnvironment_md.c index 741e014e71755a25714a48b36b9a6b8bbcc97e96..f597bff742df0afb7d672b310305fdbdf9ae8923 100644 --- a/src/solaris/native/java/lang/ProcessEnvironment_md.c +++ b/src/solaris/native/java/lang/ProcessEnvironment_md.c @@ -31,21 +31,24 @@ #ifdef __APPLE__ #include #define environ (*_NSGetEnviron()) +#else +/* This is one of the rare times it's more portable to declare an + * external symbol explicitly, rather than via a system header. + * The declaration is standardized as part of UNIX98, but there is + * no standard (not even de-facto) header file where the + * declaration is to be found. See: + * http://www.opengroup.org/onlinepubs/009695399/functions/environ.html + * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html + * + * "All identifiers in this volume of IEEE Std 1003.1-2001, except + * environ, are defined in at least one of the headers" (!) + */ +extern char **environ; #endif JNIEXPORT jobjectArray JNICALL Java_java_lang_ProcessEnvironment_environ(JNIEnv *env, jclass ign) { - /* This is one of the rare times it's more portable to declare an - * external symbol explicitly, rather than via a system header. - * The declaration is standardized as part of UNIX98, but there is - * no standard (not even de-facto) header file where the - * declaration is to be found. See: - * http://www.opengroup.org/onlinepubs/007908799/xbd/envvar.html */ -#ifndef __APPLE__ - extern char ** environ; /* environ[i] looks like: VAR=VALUE\0 */ -#endif - jsize count = 0; jsize i, j; jobjectArray result; diff --git a/src/solaris/native/java/lang/UNIXProcess_md.c b/src/solaris/native/java/lang/UNIXProcess_md.c index 5aff82fb0c43c383de09f0cb4ff111148b3f27db..f5f81a128fd885aa4fa9bbff99d4549fe1153161 100644 --- a/src/solaris/native/java/lang/UNIXProcess_md.c +++ b/src/solaris/native/java/lang/UNIXProcess_md.c @@ -52,6 +52,19 @@ #ifdef __APPLE__ #include #define environ (*_NSGetEnviron()) +#else +/* This is one of the rare times it's more portable to declare an + * external symbol explicitly, rather than via a system header. + * The declaration is standardized as part of UNIX98, but there is + * no standard (not even de-facto) header file where the + * declaration is to be found. See: + * http://www.opengroup.org/onlinepubs/009695399/functions/environ.html + * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html + * + * "All identifiers in this volume of IEEE Std 1003.1-2001, except + * environ, are defined in at least one of the headers" (!) + */ +extern char **environ; #endif /* @@ -152,19 +165,6 @@ } while((_result == -1) && (errno == EINTR)); \ } while(0) -/* This is one of the rare times it's more portable to declare an - * external symbol explicitly, rather than via a system header. - * The declaration is standardized as part of UNIX98, but there is - * no standard (not even de-facto) header file where the - * declaration is to be found. See: - * http://www.opengroup.org/onlinepubs/009695399/functions/environ.html - * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html - * - * "All identifiers in this volume of IEEE Std 1003.1-2001, except - * environ, are defined in at least one of the headers" (!) - */ -extern char **environ; - static void setSIGCHLDHandler(JNIEnv *env) @@ -241,52 +241,41 @@ countOccurrences(const char *s, char c) } static const char * const * -splitPath(JNIEnv *env, const char *path) +effectivePathv(JNIEnv *env) { - const char *p, *q; - char **pathv; + char *p; int i; + const char *path = effectivePath(); int count = countOccurrences(path, ':') + 1; - - pathv = NEW(char*, count+1); - pathv[count] = NULL; - for (p = path, i = 0; i < count; i++, p = q + 1) { - for (q = p; (*q != ':') && (*q != '\0'); q++) - ; - if (q == p) /* empty PATH component => "." */ - pathv[i] = "./"; - else { - int addSlash = ((*(q - 1)) != '/'); - pathv[i] = NEW(char, q - p + addSlash + 1); - memcpy(pathv[i], p, q - p); - if (addSlash) - pathv[i][q - p] = '/'; - pathv[i][q - p + addSlash] = '\0'; - } + size_t pathvsize = sizeof(const char *) * (count+1); + size_t pathsize = strlen(path) + 1; + const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize); + + if (pathv == NULL) + return NULL; + p = (char *) pathv + pathvsize; + memcpy(p, path, pathsize); + /* split PATH by replacing ':' with NULs; empty components => "." */ + for (i = 0; i < count; i++) { + char *q = p + strcspn(p, ":"); + pathv[i] = (p == q) ? "." : p; + *q = '\0'; + p = q + 1; } - return (const char * const *) pathv; + pathv[count] = NULL; + return pathv; } /** - * Cached value of JVM's effective PATH. + * The cached and split version of the JDK's effective PATH. * (We don't support putenv("PATH=...") in native code) */ -static const char *parentPath; - -/** - * Split, canonicalized version of parentPath - */ static const char * const *parentPathv; -static jfieldID field_exitcode; - JNIEXPORT void JNICALL -Java_java_lang_UNIXProcess_initIDs(JNIEnv *env, jclass clazz) +Java_java_lang_UNIXProcess_init(JNIEnv *env, jclass clazz) { - field_exitcode = (*env)->GetFieldID(env, clazz, "exitcode", "I"); - - parentPath = effectivePath(); - parentPathv = splitPath(env, parentPath); + parentPathv = effectivePathv(env); setSIGCHLDHandler(env); } @@ -486,6 +475,9 @@ throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) } /* ASCII Decimal representation uses 2.4 times as many bits as binary. */ errmsg = NEW(char, strlen(format) + strlen(detail) + 3 * sizeof(errnum)); + if (errmsg == NULL) + return; + sprintf(errmsg, format, errnum, detail); s = JNU_NewStringPlatform(env, errmsg); if (s != NULL) { @@ -590,11 +582,13 @@ JDK_execvpe(const char *file, for (dirs = parentPathv; *dirs; dirs++) { const char * dir = *dirs; int dirlen = strlen(dir); - if (filelen + dirlen + 1 >= PATH_MAX) { + if (filelen + dirlen + 2 >= PATH_MAX) { errno = ENAMETOOLONG; continue; } memcpy(expanded_file, dir, dirlen); + if (expanded_file[dirlen - 1] != '/') + expanded_file[dirlen++] = '/'; memcpy(expanded_file + dirlen, file, filelen); expanded_file[dirlen + filelen] = '\0'; execve_with_shell_fallback(expanded_file, argv, envp); diff --git a/src/solaris/native/sun/awt/awt_LoadLibrary.c b/src/solaris/native/sun/awt/awt_LoadLibrary.c index cdb0e8f9d08ad568af4950c5d2eaba12b8b4cda6..378db5850ab5ea822894e6e55c91cee858c447ca 100644 --- a/src/solaris/native/sun/awt/awt_LoadLibrary.c +++ b/src/solaris/native/sun/awt/awt_LoadLibrary.c @@ -43,7 +43,7 @@ static void *awtHandle = NULL; -typedef JNIEXPORT jint JNICALL JNI_OnLoad_type(JavaVM *vm, void *reserved); +typedef jint JNICALL JNI_OnLoad_type(JavaVM *vm, void *reserved); /* Initialize the Java VM instance variable when the library is first loaded */ @@ -206,7 +206,7 @@ Java_sun_awt_motif_XsessionWMcommand(JNIEnv *env, jobject this, jobject frame, jstring jcommand) { /* type of the old backdoor function */ - typedef JNIEXPORT void JNICALL + typedef void JNICALL XsessionWMcommand_type(JNIEnv *env, jobject this, jobject frame, jstring jcommand); @@ -234,7 +234,7 @@ Java_sun_awt_motif_XsessionWMcommand(JNIEnv *env, jobject this, JNIEXPORT void JNICALL Java_sun_awt_motif_XsessionWMcommand_New(JNIEnv *env, jobjectArray jargv) { - typedef JNIEXPORT void JNICALL + typedef void JNICALL XsessionWMcommand_New_type(JNIEnv *env, jobjectArray jargv); static XsessionWMcommand_New_type *XsessionWMcommand = NULL; diff --git a/test/demo/zipfs/ZipFSTester.java b/test/demo/zipfs/ZipFSTester.java index 0d512cc1f98e9d6714a5110746ef87c7a6300123..f4937a6fdb5231672d82d92efe16ba26d80b4ccb 100644 --- a/test/demo/zipfs/ZipFSTester.java +++ b/test/demo/zipfs/ZipFSTester.java @@ -138,14 +138,31 @@ public class ZipFSTester { Path dst3 = Paths.get(tmpName + "_Tmp"); Files.move(dst2, dst3); checkEqual(src, dst3); + if (Files.exists(dst2)) + throw new RuntimeException("Failed!"); + + // copyback + move + Files.copy(dst3, dst); + Path dst4 = getPathWithParents(fs, tmpName + "_Tmp0"); + Files.move(dst, dst4); + checkEqual(src, dst4); // delete - if (Files.exists(dst2)) + Files.delete(dst4); + if (Files.exists(dst4)) throw new RuntimeException("Failed!"); Files.delete(dst3); if (Files.exists(dst3)) throw new RuntimeException("Failed!"); + // move (existing entry) + Path dst5 = fs.getPath("META-INF/MANIFEST.MF"); + if (Files.exists(dst5)) { + Path dst6 = fs.getPath("META-INF/MANIFEST.MF_TMP"); + Files.move(dst5, dst6); + walk(fs.getPath("/")); + } + // newInputStream on dir Path parent = dst2.getParent(); try { diff --git a/test/demo/zipfs/basic.sh b/test/demo/zipfs/basic.sh index 40583d100428e55900ba904c4a9dc7ce5f666a6d..4b814f9849eda63e3b9ba2bc4afc6ae1339b29f4 100644 --- a/test/demo/zipfs/basic.sh +++ b/test/demo/zipfs/basic.sh @@ -22,7 +22,7 @@ # # @test # @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596 -# 7157656 +# 7157656 8002390 # @summary Test ZipFileSystem demo # @build Basic PathOps ZipFSTester # @run shell basic.sh diff --git a/test/java/lang/invoke/lambda/LambdaClassFinal.java b/test/java/lang/invoke/lambda/LambdaClassFinal.java new file mode 100644 index 0000000000000000000000000000000000000000..58e913366610d386ffc1c6323b4a0a9f2964886c --- /dev/null +++ b/test/java/lang/invoke/lambda/LambdaClassFinal.java @@ -0,0 +1,58 @@ +/* + * 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 8012028 + * @summary Generated Lambda implementing class should be final + */ + +import java.lang.reflect.Modifier; +import java.io.Serializable; + +public class LambdaClassFinal { + + interface I { + void m(); + } + + interface Iser extends Serializable { + void m(); + } + + static void assertTrue(boolean cond) { + if (!cond) + throw new AssertionError(); + } + + public static void main(String[] args) throws Exception { + new LambdaClassFinal().test(); + } + + void test() throws Exception { + I lam = () -> { }; + assertTrue((lam.getClass().getModifiers() & Modifier.FINAL) != 0); + Iser slam = () -> { }; + assertTrue((slam.getClass().getModifiers() & Modifier.FINAL) != 0); + } +} diff --git a/test/java/lang/invoke/lambda/LambdaClassSynthetic.java b/test/java/lang/invoke/lambda/LambdaClassSynthetic.java new file mode 100644 index 0000000000000000000000000000000000000000..38cb3786dffd2cadf6405f850f10a28e84da8779 --- /dev/null +++ b/test/java/lang/invoke/lambda/LambdaClassSynthetic.java @@ -0,0 +1,58 @@ +/* + * 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 8008941 + * @summary Generated Lambda implementing class should be synthetic + */ + +import java.lang.reflect.Modifier; +import java.io.Serializable; + +public class LambdaClassSynthetic { + + interface I { + void m(); + } + + interface Iser extends Serializable { + void m(); + } + + static void assertTrue(boolean cond) { + if (!cond) + throw new AssertionError(); + } + + public static void main(String[] args) throws Exception { + new LambdaClassFinal().test(); + } + + void test() throws Exception { + I lam = () -> { }; + assertTrue(lam.getClass().isSynthetic()); + Iser slam = () -> { }; + assertTrue(slam.getClass().isSynthetic()); + } +} diff --git a/test/java/nio/file/attribute/FileTime/Basic.java b/test/java/nio/file/attribute/FileTime/Basic.java index 9a8bdf68205e9cfb9b5831ba21e1821e62f45290..52eba9d1737877a3a6adeed6c0807f609dd34be9 100644 --- a/test/java/nio/file/attribute/FileTime/Basic.java +++ b/test/java/nio/file/attribute/FileTime/Basic.java @@ -22,14 +22,17 @@ */ /* @test - * @bug 6844313 + * @bug 6844313 8011647 * @summary Unit test for java.nio.file.FileTime */ + import java.nio.file.attribute.FileTime; +import java.time.Instant; import java.util.concurrent.TimeUnit; import static java.util.concurrent.TimeUnit.*; import java.util.Random; +import java.util.EnumSet; public class Basic { @@ -40,27 +43,59 @@ public class Basic { long tomorrowInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) + 1; long yesterdayInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) - 1; + Instant nowInstant = Instant.ofEpochMilli(now); + // equals eq(now, MILLISECONDS, now, MILLISECONDS); eq(now, MILLISECONDS, now*1000L, MICROSECONDS); neq(now, MILLISECONDS, 0, MILLISECONDS); neq(now, MILLISECONDS, 0, MICROSECONDS); + eq(nowInstant, now, MILLISECONDS); + eq(nowInstant, now*1000L, MICROSECONDS); + neq(nowInstant, 0, MILLISECONDS); + neq(nowInstant, 0, MICROSECONDS); + // compareTo cmp(now, MILLISECONDS, now, MILLISECONDS, 0); cmp(now, MILLISECONDS, now*1000L, MICROSECONDS, 0); cmp(now, MILLISECONDS, now-1234, MILLISECONDS, 1); cmp(now, MILLISECONDS, now+1234, MILLISECONDS, -1); + cmp(tomorrowInDays, DAYS, now, MILLISECONDS, 1); cmp(now, MILLISECONDS, tomorrowInDays, DAYS, -1); cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1); cmp(now, MILLISECONDS, yesterdayInDays, DAYS, 1); cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1); + cmp(Long.MAX_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, 1); cmp(Long.MAX_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, 1); cmp(Long.MIN_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, -1); cmp(Long.MIN_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, -1); + cmp(Instant.MIN, Long.MIN_VALUE, DAYS, 1); + cmp(Instant.MIN, Long.MIN_VALUE, HOURS, 1); + cmp(Instant.MIN, Long.MIN_VALUE, MINUTES, 1); + cmp(Instant.MIN, Long.MIN_VALUE, SECONDS, 1); + cmp(Instant.MIN, Instant.MIN.getEpochSecond() - 1, SECONDS, 1); + cmp(Instant.MIN, Instant.MIN.getEpochSecond() - 100, SECONDS, 1); + cmp(Instant.MIN, Instant.MIN.getEpochSecond(), SECONDS, 0); + + cmp(Instant.MAX, Long.MAX_VALUE, DAYS, -1); + cmp(Instant.MAX, Long.MAX_VALUE, HOURS, -1); + cmp(Instant.MAX, Long.MAX_VALUE, MINUTES, -1); + cmp(Instant.MAX, Long.MAX_VALUE, SECONDS, -1); + cmp(Instant.MAX, Instant.MAX.getEpochSecond() + 1, SECONDS, -1); + cmp(Instant.MAX, Instant.MAX.getEpochSecond() + 100, SECONDS, -1); + cmp(Instant.MAX, Instant.MAX.getEpochSecond(), SECONDS, 0); + + cmp(nowInstant, now, MILLISECONDS, 0); + cmp(nowInstant, now*1000L, MICROSECONDS, 0); + cmp(nowInstant, now-1234, MILLISECONDS, 1); + cmp(nowInstant, now+1234, MILLISECONDS, -1); + cmp(nowInstant, tomorrowInDays, DAYS, -1); + cmp(nowInstant, yesterdayInDays, DAYS, 1); + // to(TimeUnit) to(MILLISECONDS.convert(1, DAYS) - 1, MILLISECONDS); to(MILLISECONDS.convert(1, DAYS) + 0, MILLISECONDS); @@ -77,6 +112,64 @@ public class Basic { to(Long.MAX_VALUE, unit); } + // toInstant() + int N = 1000; + for (TimeUnit unit : EnumSet.allOf(TimeUnit.class)) { + for (int i = 0; i < N; i++) { + long value = rand.nextLong(); + FileTime ft = FileTime.from(value, unit); + Instant instant = ft.toInstant(); + if (instant != Instant.MIN && instant != Instant.MAX) { + eqTime(value, unit, instant); + } + } + } + for (TimeUnit unit : EnumSet.allOf(TimeUnit.class)) { + long value = Long.MIN_VALUE; + FileTime ft = FileTime.from(value, unit); + Instant instant = ft.toInstant(); + if (unit.compareTo(TimeUnit.SECONDS) < 0) { + eqTime(value, unit, instant); + } else if (!instant.equals(Instant.MIN)) { + throw new RuntimeException("should overflow to MIN"); + } + value = Long.MAX_VALUE; + ft = FileTime.from(value, unit); + instant = ft.toInstant(); + if (unit.compareTo(TimeUnit.SECONDS) < 0) { + eqTime(value, unit, instant); + } else if (!instant.equals(Instant.MAX)) { + throw new RuntimeException("should overflow to MAX"); + } + } + + // from(Instant) + final long MAX_SECOND = 31556889864403199L; + for (int i = 0; i < N; i++) { + long v = rand.nextLong(); + long secs = v % MAX_SECOND; + Instant instant = Instant.ofEpochSecond(secs, rand.nextInt(1000_000_000)); + FileTime ft = FileTime.from(instant); + if (!ft.toInstant().equals(instant) || ft.to(SECONDS) != secs) { + throw new RuntimeException("from(Instant) failed"); + } + long millis = v; + instant = Instant.ofEpochMilli(millis); + ft = FileTime.from(instant); + if (!ft.toInstant().equals(instant) || + ft.toMillis() != instant.toEpochMilli()) { + throw new RuntimeException("from(Instant) failed"); + } + long nanos = v; + ft = FileTime.from(nanos, NANOSECONDS); + secs = nanos / 1000_000_000; + nanos = nanos % 1000_000_000; + instant = Instant.ofEpochSecond(secs, nanos); + if (!ft.equals(FileTime.from(instant))) { + throw new RuntimeException("from(Instant) failed"); + } + } + // toString ts(1L, DAYS, "1970-01-02T00:00:00Z"); ts(1L, HOURS, "1970-01-01T01:00:00Z"); @@ -108,11 +201,18 @@ public class Basic { // NTFS epoch in usec. ts(-11644473600000000L, MICROSECONDS, "1601-01-01T00:00:00Z"); - // nulls + ts(Instant.MIN, "-1000000001-01-01T00:00:00Z"); + ts(Instant.MAX, "1000000000-12-31T23:59:59.999999999Z"); + try { FileTime.from(0L, null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException npe) { } + try { + FileTime.from(null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException npe) { } + FileTime time = FileTime.fromMillis(now); if (time.equals(null)) throw new RuntimeException("should not be equal to null"); @@ -120,6 +220,39 @@ public class Basic { time.compareTo(null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException npe) { } + + // Instant + toMilli() overflow + overflow(Long.MAX_VALUE, + FileTime.from(Instant.MAX).toMillis()); + overflow(Long.MAX_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1)) + .toMillis()); + overflow(Long.MIN_VALUE, + FileTime.from(Instant.MIN).toMillis()); + overflow(Long.MIN_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1)) + .toMillis()); + + // Instant + to(TimeUnit) overflow + overflow(Long.MAX_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1)) + .to(MILLISECONDS)); + overflow(Long.MAX_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000, + MILLISECONDS.toNanos(1000))) + .to(MILLISECONDS)); + overflow(Long.MIN_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1)) + .to(MILLISECONDS)); + overflow(Long.MIN_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000, + -MILLISECONDS.toNanos(1))) + .to(MILLISECONDS)); + } + + static void overflow(long minmax, long v) { + if (v != minmax) + throw new RuntimeException("saturates to Long.MIN/MAX_VALUE expected"); } static void cmp(long v1, TimeUnit u1, long v2, TimeUnit u2, int expected) { @@ -128,6 +261,12 @@ public class Basic { throw new RuntimeException("unexpected order"); } + static void cmp(Instant ins, long v2, TimeUnit u2, int expected) { + int result = FileTime.from(ins).compareTo(FileTime.from(v2, u2)); + if (result != expected) + throw new RuntimeException("unexpected order"); + } + static void eq(long v1, TimeUnit u1, long v2, TimeUnit u2) { FileTime t1 = FileTime.from(v1, u1); FileTime t2 = FileTime.from(v2, u2); @@ -137,6 +276,28 @@ public class Basic { throw new RuntimeException("hashCodes should be equal"); } + static void eq(Instant ins, long v2, TimeUnit u2) { + FileTime t1 = FileTime.from(ins); + FileTime t2 = FileTime.from(v2, u2); + if (!t1.equals(t2)) + throw new RuntimeException("not equal"); + if (t1.hashCode() != t2.hashCode()) + throw new RuntimeException("hashCodes should be equal"); + } + + static void eqTime(long value, TimeUnit unit, Instant instant) { + long secs = SECONDS.convert(value, unit); + long nanos = NANOSECONDS.convert(value - unit.convert(secs, SECONDS), unit); + if (nanos < 0) { // normalize nanoOfSecond to positive + secs -= 1; + nanos += 1000_000_000; + } + if (secs != instant.getEpochSecond() || (int)nanos != instant.getNano()) { + System.err.println(" ins=" + instant); + throw new RuntimeException("ft and instant are not the same time point"); + } + } + static void neq(long v1, TimeUnit u1, long v2, TimeUnit u2) { FileTime t1 = FileTime.from(v1, u1); FileTime t2 = FileTime.from(v2, u2); @@ -144,6 +305,13 @@ public class Basic { throw new RuntimeException("should not be equal"); } + static void neq(Instant ins, long v2, TimeUnit u2) { + FileTime t1 = FileTime.from(ins); + FileTime t2 = FileTime.from(v2, u2); + if (t1.equals(t2)) + throw new RuntimeException("should not be equal"); + } + static void to(long v, TimeUnit unit) { FileTime t = FileTime.from(v, unit); for (TimeUnit u: TimeUnit.values()) { @@ -164,4 +332,14 @@ public class Basic { throw new RuntimeException(); } } + + static void ts(Instant instant, String expected) { + String result = FileTime.from(instant).toString(); + if (!result.equals(expected)) { + System.err.format("FileTime.from(%s).toString() failed\n", instant); + System.err.format("Expected: %s\n", expected); + System.err.format(" Got: %s\n", result); + throw new RuntimeException(); + } + } } diff --git a/test/java/util/ComparatorsTest.java b/test/java/util/Comparators/BasicTest.java similarity index 84% rename from test/java/util/ComparatorsTest.java rename to test/java/util/Comparators/BasicTest.java index 1640c2d657a0dcb1a3e56958fb46f9660a699eb2..0913eb84b58cfab76e041a0bace6902bceb009ba 100644 --- a/test/java/util/ComparatorsTest.java +++ b/test/java/util/Comparators/BasicTest.java @@ -23,8 +23,8 @@ /* * @test - * @bug 8001667 - * @run testng ComparatorsTest + * @bug 8001667 8010279 + * @run testng BasicTest */ import java.util.Comparator; @@ -33,6 +33,7 @@ import java.util.AbstractMap; import java.util.Map; import org.testng.annotations.Test; +import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.ToIntFunction; import java.util.function.ToLongFunction; @@ -41,12 +42,13 @@ import java.util.function.ToDoubleFunction; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertSame; +import static org.testng.Assert.fail; /** * Unit tests for helper methods in Comparators */ @Test(groups = "unit") -public class ComparatorsTest { +public class BasicTest { private static class Thing { public final int intField; public final long longField; @@ -95,7 +97,7 @@ public class ComparatorsTest { Thing[] things = new Thing[intValues.length]; for (int i=0; i comp = Comparators.comparing(new ToIntFunction() { + Comparator comp = Comparators.comparing(new ToIntFunction() { @Override public int applyAsInt(Thing thing) { return thing.getIntField(); @@ -109,7 +111,7 @@ public class ComparatorsTest { Thing[] things = new Thing[longValues.length]; for (int i=0; i comp = Comparators.comparing(new ToLongFunction() { + Comparator comp = Comparators.comparing(new ToLongFunction() { @Override public long applyAsLong(Thing thing) { return thing.getLongField(); @@ -123,7 +125,7 @@ public class ComparatorsTest { Thing[] things = new Thing[doubleValues.length]; for (int i=0; i comp = Comparators.comparing(new ToDoubleFunction() { + Comparator comp = Comparators.comparing(new ToDoubleFunction() { @Override public double applyAsDouble(Thing thing) { return thing.getDoubleField(); @@ -350,4 +352,61 @@ public class ComparatorsTest { .apply(people[0], people[1]), people[1]); } -} \ No newline at end of file + + public void testNulls() { + try { + Comparators.naturalOrder().compare("abc", (String) null); + fail("expected NPE with naturalOrder"); + } catch (NullPointerException npe) {} + try { + Comparators.naturalOrder().compare((String) null, "abc"); + fail("expected NPE with naturalOrder"); + } catch (NullPointerException npe) {} + + try { + Comparators.reverseOrder().compare("abc", (String) null); + fail("expected NPE with naturalOrder"); + } catch (NullPointerException npe) {} + try { + Comparators.reverseOrder().compare((String) null, "abc"); + fail("expected NPE with naturalOrder"); + } catch (NullPointerException npe) {} + + try { + Comparator> cmp = Comparators.byKey(null); + fail("byKey(null) should throw NPE"); + } catch (NullPointerException npe) {} + + try { + Comparator> cmp = Comparators.byValue(null); + fail("byValue(null) should throw NPE"); + } catch (NullPointerException npe) {} + + try { + Comparator cmp = Comparators.comparing((Function) null); + fail("comparing(null) should throw NPE"); + } catch (NullPointerException npe) {} + try { + Comparator cmp = Comparators.comparing((ToIntFunction) null); + fail("comparing(null) should throw NPE"); + } catch (NullPointerException npe) {} + try { + Comparator cmp = Comparators.comparing((ToLongFunction) null); + fail("comparing(null) should throw NPE"); + } catch (NullPointerException npe) {} + try { + Comparator cmp = Comparators.comparing((ToDoubleFunction) null); + fail("comparing(null) should throw NPE"); + } catch (NullPointerException npe) {} + + try { + BinaryOperator op = Comparators.lesserOf(null); + fail("lesserOf(null) should throw NPE"); + } catch (NullPointerException npe) {} + + try { + BinaryOperator op = Comparators.greaterOf(null); + fail("lesserOf(null) should throw NPE"); + } catch (NullPointerException npe) {} + } +} diff --git a/test/java/util/Map/BasicSerialization.java b/test/java/util/Map/BasicSerialization.java new file mode 100644 index 0000000000000000000000000000000000000000..cb229d15f7b2d910fde981dc430eb96c8f29b23e --- /dev/null +++ b/test/java/util/Map/BasicSerialization.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 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 8011200 + * @run testng BasicSerialization + * @summary Ensure Maps can be serialized and deserialized. + * @author Mike Duigou + */ +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ByteArrayInputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; + +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; +import static org.testng.Assert.fail; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertSame; + +public class BasicSerialization { + + enum IntegerEnum { + + e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, + e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, + e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, + e30, e31, e32, e33, e34, e35, e36, e37, e38, e39, + e40, e41, e42, e43, e44, e45, e46, e47, e48, e49, + e50, e51, e52, e53, e54, e55, e56, e57, e58, e59, + e60, e61, e62, e63, e64, e65, e66, e67, e68, e69, + e70, e71, e72, e73, e74, e75, e76, e77, e78, e79, + e80, e81, e82, e83, e84, e85, e86, e87, e88, e89, + e90, e91, e92, e93, e94, e95, e96, e97, e98, e99, + EXTRA_KEY; + public static final int SIZE = values().length; + }; + private static final int TEST_SIZE = IntegerEnum.SIZE - 1; + /** + * Realized keys ensure that there is always a hard ref to all test objects. + */ + private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE]; + /** + * Realized values ensure that there is always a hard ref to all test + * objects. + */ + private static final String[] VALUES = new String[TEST_SIZE]; + + static { + IntegerEnum[] keys = IntegerEnum.values(); + for (int each = 0; each < TEST_SIZE; each++) { + KEYS[each] = keys[each]; + VALUES[each] = keys[each].name(); + } + } + private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY; + private static final String EXTRA_VALUE = IntegerEnum.EXTRA_KEY.name(); + + public static Map mapClone(Map map) { + Method cloneMethod; + + try { + cloneMethod = map.getClass().getMethod("clone", new Class[]{}); + } catch (NoSuchMethodException | SecurityException all) { + cloneMethod = null; + } + + if (null != cloneMethod) { + try { + Map result = (Map)cloneMethod.invoke(map, new Object[]{}); + return result; + } catch (Exception all) { + fail("clone() failed " + map.getClass().getSimpleName(), all); + return null; + } + } else { + Constructor copyConstructor; + try { + copyConstructor = (Constructor)map.getClass().getConstructor(new Class[]{Map.class}); + + Map result = (Map)copyConstructor.newInstance(new Object[]{map}); + + return result; + } catch (Exception all) { + return serialClone(map); + } + } + } + + @Test(dataProvider = "Map") + public void testSerialization(String description, Map map) { + Object foo = new Object(); + + Map clone = mapClone(map); + Map serialClone = serialClone(map); + + assertEquals(map, map, description + ":should equal self"); + assertEquals(clone, map, description + ":should equal clone"); + assertEquals(map, clone, description + ": should equal orginal map"); + assertEquals(serialClone, map, description + ": should equal deserialized clone"); + assertEquals(map, serialClone, description + ": should equal original map"); + assertEquals(serialClone, clone, description + ": deserialized clone should equal clone"); + assertEquals(clone, serialClone, description + ": clone should equal deserialized clone"); + + assertFalse(map.containsKey(EXTRA_KEY), description + ":unexpected key"); + assertFalse(clone.containsKey(EXTRA_KEY), description + ":unexpected key"); + assertFalse(serialClone.containsKey(EXTRA_KEY), description + ":unexpected key"); + map.put(EXTRA_KEY, EXTRA_VALUE); + clone.put(EXTRA_KEY, EXTRA_VALUE); + serialClone.put(EXTRA_KEY, EXTRA_VALUE); + assertTrue(map.containsKey(EXTRA_KEY), description + ":missing key"); + assertTrue(clone.containsKey(EXTRA_KEY), description + ":missing key"); + assertTrue(serialClone.containsKey(EXTRA_KEY), description + ":missing key"); + assertSame(map.get(EXTRA_KEY), EXTRA_VALUE, description + ":wrong value"); + assertSame(clone.get(EXTRA_KEY), EXTRA_VALUE, description + ":wrong value"); + assertSame(serialClone.get(EXTRA_KEY), EXTRA_VALUE, description + ":wrong value"); + + assertEquals(map, map, description + ":should equal self"); + assertEquals(clone, map, description + ":should equal clone"); + assertEquals(map, clone, description + ": should equal orginal map"); + assertEquals(serialClone, map, description + ": should equal deserialized clone"); + assertEquals(map, serialClone, description + ": should equal original map"); + assertEquals(serialClone, clone, description + ": deserialized clone should equal clone"); + assertEquals(clone, serialClone, description + ": clone should equal deserialized clone"); + } + + static byte[] serializedForm(Object obj) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + new ObjectOutputStream(baos).writeObject(obj); + return baos.toByteArray(); + } catch (IOException e) { + fail("Unexpected Exception", e); + return null; + } + } + + static Object readObject(byte[] bytes) throws IOException, ClassNotFoundException { + InputStream is = new ByteArrayInputStream(bytes); + return new ObjectInputStream(is).readObject(); + } + + @SuppressWarnings("unchecked") + static T serialClone(T obj) { + try { + return (T)readObject(serializedForm(obj)); + } catch (IOException | ClassNotFoundException e) { + fail("Unexpected Exception", e); + return null; + } + } + + @DataProvider(name = "Map", parallel = true) + private static Iterator makeMaps() { + return Arrays.asList( + // empty + new Object[]{"HashMap", new HashMap()}, + new Object[]{"LinkedHashMap", new LinkedHashMap()}, + new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(new HashMap(), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(new HashMap())}, + // null hostile + new Object[]{"EnumMap", new EnumMap(IntegerEnum.class)}, + new Object[]{"Hashtable", new Hashtable()}, + new Object[]{"TreeMap", new TreeMap()}, + new Object[]{"ConcurrentHashMap", new ConcurrentHashMap()}, + new Object[]{"ConcurrentSkipListMap", new ConcurrentSkipListMap()}, + new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(new ConcurrentHashMap(), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(new EnumMap(IntegerEnum.class))}, + // filled + new Object[]{"HashMap", fillMap(new HashMap())}, + new Object[]{"LinkedHashMap", fillMap(new LinkedHashMap())}, + new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(fillMap(new HashMap()), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(fillMap(new HashMap()))}, + // null hostile + new Object[]{"EnumMap", fillMap(new EnumMap(IntegerEnum.class))}, + new Object[]{"Hashtable", fillMap(new Hashtable())}, + new Object[]{"TreeMap", fillMap(new TreeMap())}, + new Object[]{"ConcurrentHashMap", fillMap(new ConcurrentHashMap())}, + new Object[]{"ConcurrentSkipListMap", fillMap(new ConcurrentSkipListMap())}, + new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(fillMap(new ConcurrentHashMap()), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(fillMap(new EnumMap(IntegerEnum.class)))}).iterator(); + } + + private static Map fillMap(Map result) { + for (int each = 0; each < TEST_SIZE; each++) { + result.put(KEYS[each], VALUES[each]); + } + + return result; + } +} diff --git a/test/java/util/Objects/BasicObjectsTest.java b/test/java/util/Objects/BasicObjectsTest.java index 695b57a96bfc46415a8004edf306104b0c0eed7c..7f93dc4b9bcc647903b73faf3113eedba09a6734 100644 --- a/test/java/util/Objects/BasicObjectsTest.java +++ b/test/java/util/Objects/BasicObjectsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -23,12 +23,13 @@ /* * @test - * @bug 6797535 6889858 6891113 + * @bug 6797535 6889858 6891113 8011800 * @summary Basic tests for methods in java.util.Objects * @author Joseph D. Darcy */ import java.util.*; +import java.util.function.*; public class BasicObjectsTest { public static void main(String... args) { @@ -40,7 +41,7 @@ public class BasicObjectsTest { errors += testToString(); errors += testToString2(); errors += testCompare(); - errors += testNonNull(); + errors += testRequireNonNull(); if (errors > 0 ) throw new RuntimeException(); } @@ -158,49 +159,54 @@ public class BasicObjectsTest { return errors; } - private static int testNonNull() { + private static int testRequireNonNull() { int errors = 0; - String s; - // Test 1-arg variant - try { - s = Objects.requireNonNull("pants"); - if (s != "pants") { - System.err.printf("1-arg non-null failed to return its arg"); - errors++; - } - } catch (NullPointerException e) { - System.err.printf("1-arg nonNull threw unexpected NPE"); - errors++; - } + final String RNN_1 = "1-arg requireNonNull"; + final String RNN_2 = "2-arg requireNonNull"; + final String RNN_3 = "Supplier requireNonNull"; - try { - s = Objects.requireNonNull(null); - System.err.printf("1-arg nonNull failed to throw NPE"); - errors++; - } catch (NullPointerException e) { - // Expected - } + Function rnn1 = s -> Objects.requireNonNull(s); + Function rnn2 = s -> Objects.requireNonNull(s, "trousers"); + Function rnn3 = s -> Objects.requireNonNull(s, () -> "trousers"); + + errors += testRNN_NonNull(rnn1, RNN_1); + errors += testRNN_NonNull(rnn2, RNN_2); + errors += testRNN_NonNull(rnn3, RNN_3); + + errors += testRNN_Null(rnn1, RNN_1, null); + errors += testRNN_Null(rnn2, RNN_2, "trousers"); + errors += testRNN_Null(rnn3, RNN_3, "trousers"); + return errors; + } - // Test 2-arg variant + private static int testRNN_NonNull(Function testFunc, + String testFuncName) { + int errors = 0; try { - s = Objects.requireNonNull("pants", "trousers"); + String s = testFunc.apply("pants"); if (s != "pants") { - System.err.printf("2-arg nonNull failed to return its arg"); + System.err.printf(testFuncName + " failed to return its arg"); errors++; } } catch (NullPointerException e) { - System.err.printf("2-arg nonNull threw unexpected NPE"); + System.err.printf(testFuncName + " threw unexpected NPE"); errors++; } + return errors; + } + private static int testRNN_Null(Function testFunc, + String testFuncName, + String expectedMessage) { + int errors = 0; try { - s = Objects.requireNonNull(null, "pantaloons"); - System.err.printf("2-arg nonNull failed to throw NPE"); + String s = testFunc.apply(null); + System.err.printf(testFuncName + " failed to throw NPE"); errors++; } catch (NullPointerException e) { - if (e.getMessage() != "pantaloons") { - System.err.printf("2-arg nonNull threw NPE w/ bad detail msg"); + if (e.getMessage() != expectedMessage) { + System.err.printf(testFuncName + " threw NPE w/ bad detail msg"); errors++; } } diff --git a/test/java/util/concurrent/CompletableFuture/Basic.java b/test/java/util/concurrent/CompletableFuture/Basic.java index e8ed70658d97c6958d4ca289897da865206d42e3..a35c5f4ec558afc3149fb47a1c75bf4e5a374e8b 100644 --- a/test/java/util/concurrent/CompletableFuture/Basic.java +++ b/test/java/util/concurrent/CompletableFuture/Basic.java @@ -486,40 +486,40 @@ public class Basic { CompletableFuture cf1 = supplyAsync(() -> 1); CompletableFuture cf2 = supplyAsync(() -> 2); cf3 = cf1.applyToEither(cf2, (x) -> { check(x == 1 || x == 2); return x; }); - check(cf1.isDone() || cf2.isDone()); checkCompletedNormally(cf3, new Object[] {1, 2}); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> 2); cf3 = cf1.applyToEitherAsync(cf2, (x) -> { check(x == 1 || x == 2); return x; }); - check(cf1.isDone() || cf2.isDone()); checkCompletedNormally(cf3, new Object[] {1, 2}); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> 2); cf3 = cf1.applyToEitherAsync(cf2, (x) -> { check(x == 1 || x == 2); return x; }, executor); - check(cf1.isDone() || cf2.isDone()); checkCompletedNormally(cf3, new Object[] {1, 2}); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> { throw new RuntimeException(); }); cf2 = supplyAsync(() -> 2); cf3 = cf1.applyToEither(cf2, (x) -> { check(x == 2); return x; }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == 1); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> { throw new RuntimeException(); }); cf3 = cf1.applyToEitherAsync(cf2, (x) -> { check(x == 1); return x; }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == 1); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> { throw new RuntimeException(); }); cf2 = supplyAsync(() -> { throw new RuntimeException(); }); cf3 = cf1.applyToEitherAsync(cf2, (x) -> { fail(); return x; }); - check(cf1.isDone() || cf2.isDone()); checkCompletedExceptionally(cf3); + check(cf1.isDone() || cf2.isDone()); } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- @@ -531,45 +531,45 @@ public class Basic { CompletableFuture cf1 = supplyAsync(() -> 1); CompletableFuture cf2 = supplyAsync(() -> 2); cf3 = cf1.acceptEither(cf2, (x) -> { check(x == 1 || x == 2); atomicInt.incrementAndGet(); }); - check(cf1.isDone() || cf2.isDone()); checkCompletedNormally(cf3, null); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> 2); cf3 = cf1.acceptEitherAsync(cf2, (x) -> { check(x == 1 || x == 2); atomicInt.incrementAndGet(); }); - check(cf1.isDone() || cf2.isDone()); checkCompletedNormally(cf3, null); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> 2); cf3 = cf2.acceptEitherAsync(cf1, (x) -> { check(x == 1 || x == 2); atomicInt.incrementAndGet(); }, executor); - check(cf1.isDone() || cf2.isDone()); checkCompletedNormally(cf3, null); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); cf1 = supplyAsync(() -> { throw new RuntimeException(); }); cf2 = supplyAsync(() -> 2); cf3 = cf2.acceptEitherAsync(cf1, (x) -> { check(x == 2); }, executor); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == null); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> { throw new RuntimeException(); }); cf3 = cf2.acceptEitherAsync(cf1, (x) -> { check(x == 1); }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == null); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> { throw new RuntimeException(); }); cf2 = supplyAsync(() -> { throw new RuntimeException(); }); cf3 = cf2.acceptEitherAsync(cf1, (x) -> { fail(); }); - check(cf1.isDone() || cf2.isDone()); checkCompletedExceptionally(cf3); + check(cf1.isDone() || cf2.isDone()); } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- @@ -581,50 +581,50 @@ public class Basic { CompletableFuture cf1 = runAsync(() -> { }); CompletableFuture cf2 = runAsync(() -> { }); cf3 = cf1.runAfterEither(cf2, () -> { atomicInt.incrementAndGet(); }); - check(cf1.isDone() || cf2.isDone()); checkCompletedNormally(cf3, null); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { }); cf2 = runAsync(() -> { }); cf3 = cf1.runAfterEitherAsync(cf2, () -> { atomicInt.incrementAndGet(); }); - check(cf1.isDone() || cf2.isDone()); checkCompletedNormally(cf3, null); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { }); cf2 = runAsync(() -> { }); cf3 = cf2.runAfterEitherAsync(cf1, () -> { atomicInt.incrementAndGet(); }, executor); - check(cf1.isDone() || cf2.isDone()); checkCompletedNormally(cf3, null); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { throw new RuntimeException(); }); cf2 = runAsync(() -> { }); cf3 = cf2.runAfterEither(cf1, () -> { atomicInt.incrementAndGet(); }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == null); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { }); cf2 = runAsync(() -> { throw new RuntimeException(); }); cf3 = cf1.runAfterEitherAsync(cf2, () -> { atomicInt.incrementAndGet(); }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == null); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { throw new RuntimeException(); }); cf2 = runAsync(() -> { throw new RuntimeException(); }); cf3 = cf2.runAfterEitherAsync(cf1, () -> { atomicInt.incrementAndGet(); }, executor); - check(cf1.isDone() || cf2.isDone()); checkCompletedExceptionally(cf3); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == before); } catch (Throwable t) { unexpected(t); } @@ -670,16 +670,16 @@ public class Basic { //---------------------------------------------------------------- // anyOf tests //---------------------------------------------------------------- - //try { - // CompletableFuture cf3; - // for (int k=0; k < 10; k++){ - // CompletableFuture cf1 = supplyAsync(() -> 1); - // CompletableFuture cf2 = supplyAsync(() -> 2); - // cf3 = CompletableFuture.anyOf(cf1, cf2); - // check(cf1.isDone() || cf2.isDone()); - // checkCompletedNormally(cf3, new Object[] {1, 2}); - // } - //} catch (Throwable t) { unexpected(t); } + try { + CompletableFuture cf3; + for (int k=0; k < 10; k++){ + CompletableFuture cf1 = supplyAsync(() -> 1); + CompletableFuture cf2 = supplyAsync(() -> 2); + cf3 = CompletableFuture.anyOf(cf1, cf2); + checkCompletedNormally(cf3, new Object[] {1, 2}); + check(cf1.isDone() || cf2.isDone()); + } + } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- // allOf tests