# HG changeset patch # User vinnie # Date 1366101898 25200 # Node ID 6f80a6584fb912aa1857b2eb46d43712e8bd8062 # Parent 5435f112e5ea1d3ad4b985aacd1b8fdd73d0db12# Parent baaa706d76771c2b14c3ec09be4c675f8dcdbe04 Merge diff -r 5435f112e5ea -r 6f80a6584fb9 make/java/java/mapfile-vers --- a/make/java/java/mapfile-vers Fri Apr 12 10:42:50 2013 -0700 +++ b/make/java/java/mapfile-vers Tue Apr 16 01:44:58 2013 -0700 @@ -217,7 +217,7 @@ 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 -r 5435f112e5ea -r 6f80a6584fb9 makefiles/mapfiles/libjava/mapfile-vers --- a/makefiles/mapfiles/libjava/mapfile-vers Fri Apr 12 10:42:50 2013 -0700 +++ b/makefiles/mapfiles/libjava/mapfile-vers Tue Apr 16 01:44:58 2013 -0700 @@ -217,7 +217,7 @@ 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 -r 5435f112e5ea -r 6f80a6584fb9 src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java --- a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Tue Apr 16 01:44:58 2013 -0700 @@ -184,7 +184,7 @@ for (int i=0; i { /** + * 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 since the epoch; can be negative. */ private final long value; /** - * The unit of granularity to interpret the value. + * The value as Instant (created lazily, if not from an instant) */ - private final TimeUnit unit; + private Instant instant; /** * The value return by toString (created lazily) @@ -66,27 +72,12 @@ private String valueAsString; /** - * The value in days and excess nanos (created lazily) - */ - private DaysAndNanos daysAndNanos; - - /** - * Returns a DaysAndNanos object representing the value. - */ - private DaysAndNanos asDaysAndNanos() { - if (daysAndNanos == null) - daysAndNanos = new DaysAndNanos(value, unit); - return daysAndNanos; - } - - /** * 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 @@ * @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 @@ * @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 @@ * 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 @@ * @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 @@ */ @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 @@ @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(); + } + 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; + } + 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); } - - // 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; + sb.append('Z'); + valueAsString = sb.toString(); } - 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"); - } - 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; - } + return valueAsString; } } diff -r 5435f112e5ea -r 6f80a6584fb9 src/share/classes/java/util/ArrayList.java --- a/src/share/classes/java/util/ArrayList.java Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/classes/java/util/ArrayList.java Tue Apr 16 01:44:58 2013 -0700 @@ -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 @@ -105,8 +105,20 @@ 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 @@ * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { - this(10); + super(); + this.elementData = EMPTY_ELEMENTDATA; } /** @@ -162,8 +175,7 @@ */ public void trimToSize() { modCount++; - int oldCapacity = elementData.length; - if (size < oldCapacity) { + if (size < elementData.length) { elementData = Arrays.copyOf(elementData, size); } } @@ -176,12 +188,29 @@ * @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 @@ 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 @@ 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 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 @@ 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 @@ 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 @@ 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