From 7d471dd141cca96be282d0dbe3019011068cc5ab Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Fri, 9 Aug 2013 09:05:20 -0700 Subject: [PATCH 01/44] 8023681: Fix raw type warning caused by Sink Reviewed-by: mduigou, briangoetz --- .../classes/java/util/stream/Collectors.java | 40 +++++++++---------- .../classes/java/util/stream/DistinctOps.java | 4 +- .../java/util/stream/DoublePipeline.java | 15 ++++--- .../classes/java/util/stream/IntPipeline.java | 21 +++++----- .../java/util/stream/LongPipeline.java | 19 ++++----- .../java/util/stream/ReferencePipeline.java | 26 ++++++------ .../share/classes/java/util/stream/Sink.java | 28 ++++++------- .../classes/java/util/stream/SliceOps.java | 25 +++++++----- .../classes/java/util/stream/SortedOps.java | 34 ++++++++-------- 9 files changed, 101 insertions(+), 111 deletions(-) diff --git a/jdk/src/share/classes/java/util/stream/Collectors.java b/jdk/src/share/classes/java/util/stream/Collectors.java index 27c7c83ead4..bdbd8ad0774 100644 --- a/jdk/src/share/classes/java/util/stream/Collectors.java +++ b/jdk/src/share/classes/java/util/stream/Collectors.java @@ -137,6 +137,11 @@ public final class Collectors { return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }; } + @SuppressWarnings("unchecked") + private static Function castingIdentity() { + return i -> (R) i; + } + /** * Simple implementation class for {@code Collector}. * @@ -166,7 +171,7 @@ public final class Collectors { BiConsumer accumulator, BinaryOperator combiner, Set characteristics) { - this(supplier, accumulator, combiner, i -> (R) i, characteristics); + this(supplier, accumulator, combiner, castingIdentity(), characteristics); } @Override @@ -209,7 +214,7 @@ public final class Collectors { */ public static > Collector toCollection(Supplier collectionFactory) { - return new CollectorImpl<>(collectionFactory, Collection::add, + return new CollectorImpl<>(collectionFactory, Collection::add, (r1, r2) -> { r1.addAll(r2); return r1; }, CH_ID); } @@ -1046,30 +1051,23 @@ public final class Collectors { public static Collector> partitioningBy(Predicate predicate, Collector downstream) { - @SuppressWarnings("unchecked") - BiConsumer downstreamAccumulator = (BiConsumer) downstream.accumulator(); - BiConsumer, T> accumulator = (result, t) -> { - Partition asPartition = ((Partition) result); - downstreamAccumulator.accept(predicate.test(t) ? asPartition.forTrue : asPartition.forFalse, t); - }; + BiConsumer downstreamAccumulator = downstream.accumulator(); + BiConsumer, T> accumulator = (result, t) -> + downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t); BinaryOperator op = downstream.combiner(); - BinaryOperator> merger = (m1, m2) -> { - Partition left = (Partition) m1; - Partition right = (Partition) m2; - return new Partition<>(op.apply(left.forTrue, right.forTrue), - op.apply(left.forFalse, right.forFalse)); - }; - Supplier> supplier = () -> new Partition<>(downstream.supplier().get(), - downstream.supplier().get()); + BinaryOperator> merger = (left, right) -> + new Partition<>(op.apply(left.forTrue, right.forTrue), + op.apply(left.forFalse, right.forFalse)); + Supplier> supplier = () -> + new Partition<>(downstream.supplier().get(), + downstream.supplier().get()); if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, merger, CH_ID); } else { - Function, Map> finisher = (Map par) -> { - Partition asAPartition = (Partition) par; - return new Partition<>(downstream.finisher().apply(asAPartition.forTrue), - downstream.finisher().apply(asAPartition.forFalse)); - }; + Function, Map> finisher = par -> + new Partition<>(downstream.finisher().apply(par.forTrue), + downstream.finisher().apply(par.forFalse)); return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID); } } diff --git a/jdk/src/share/classes/java/util/stream/DistinctOps.java b/jdk/src/share/classes/java/util/stream/DistinctOps.java index 69d231f88f5..1c4dfee5d67 100644 --- a/jdk/src/share/classes/java/util/stream/DistinctOps.java +++ b/jdk/src/share/classes/java/util/stream/DistinctOps.java @@ -101,7 +101,7 @@ final class DistinctOps { if (StreamOpFlag.DISTINCT.isKnown(flags)) { return sink; } else if (StreamOpFlag.SORTED.isKnown(flags)) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { boolean seenNull; T lastSeen; @@ -132,7 +132,7 @@ final class DistinctOps { } }; } else { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { Set seen; @Override diff --git a/jdk/src/share/classes/java/util/stream/DoublePipeline.java b/jdk/src/share/classes/java/util/stream/DoublePipeline.java index 44c8ff0f5e7..f894fa0abb9 100644 --- a/jdk/src/share/classes/java/util/stream/DoublePipeline.java +++ b/jdk/src/share/classes/java/util/stream/DoublePipeline.java @@ -191,7 +191,7 @@ abstract class DoublePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedDouble(sink) { + return new Sink.ChainedDouble(sink) { @Override public void accept(double t) { downstream.accept(mapper.applyAsDouble(t)); @@ -208,9 +208,8 @@ abstract class DoublePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedDouble(sink) { + return new Sink.ChainedDouble(sink) { @Override - @SuppressWarnings("unchecked") public void accept(double t) { downstream.accept(mapper.apply(t)); } @@ -226,7 +225,7 @@ abstract class DoublePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedDouble(sink) { + return new Sink.ChainedDouble(sink) { @Override public void accept(double t) { downstream.accept(mapper.applyAsInt(t)); @@ -243,7 +242,7 @@ abstract class DoublePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedDouble(sink) { + return new Sink.ChainedDouble(sink) { @Override public void accept(double t) { downstream.accept(mapper.applyAsLong(t)); @@ -259,7 +258,7 @@ abstract class DoublePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedDouble(sink) { + return new Sink.ChainedDouble(sink) { @Override public void begin(long size) { downstream.begin(-1); @@ -296,7 +295,7 @@ abstract class DoublePipeline StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedDouble(sink) { + return new Sink.ChainedDouble(sink) { @Override public void begin(long size) { downstream.begin(-1); @@ -319,7 +318,7 @@ abstract class DoublePipeline 0) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedDouble(sink) { + return new Sink.ChainedDouble(sink) { @Override public void accept(double t) { consumer.accept(t); diff --git a/jdk/src/share/classes/java/util/stream/IntPipeline.java b/jdk/src/share/classes/java/util/stream/IntPipeline.java index d380e4a3bf5..f7dc79317d3 100644 --- a/jdk/src/share/classes/java/util/stream/IntPipeline.java +++ b/jdk/src/share/classes/java/util/stream/IntPipeline.java @@ -189,9 +189,8 @@ abstract class IntPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { @Override - @SuppressWarnings("unchecked") public void accept(int t) { downstream.accept((long) t); } @@ -206,9 +205,8 @@ abstract class IntPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { @Override - @SuppressWarnings("unchecked") public void accept(int t) { downstream.accept((double) t); } @@ -229,7 +227,7 @@ abstract class IntPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { @Override public void accept(int t) { downstream.accept(mapper.applyAsInt(t)); @@ -246,9 +244,8 @@ abstract class IntPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { @Override - @SuppressWarnings("unchecked") public void accept(int t) { downstream.accept(mapper.apply(t)); } @@ -264,7 +261,7 @@ abstract class IntPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { @Override public void accept(int t) { downstream.accept(mapper.applyAsLong(t)); @@ -281,7 +278,7 @@ abstract class IntPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { @Override public void accept(int t) { downstream.accept(mapper.applyAsDouble(t)); @@ -297,7 +294,7 @@ abstract class IntPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { @Override public void begin(long size) { downstream.begin(-1); @@ -334,7 +331,7 @@ abstract class IntPipeline StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { @Override public void begin(long size) { downstream.begin(-1); @@ -357,7 +354,7 @@ abstract class IntPipeline 0) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { @Override public void accept(int t) { consumer.accept(t); diff --git a/jdk/src/share/classes/java/util/stream/LongPipeline.java b/jdk/src/share/classes/java/util/stream/LongPipeline.java index 083f7bb8b2b..3c199feab59 100644 --- a/jdk/src/share/classes/java/util/stream/LongPipeline.java +++ b/jdk/src/share/classes/java/util/stream/LongPipeline.java @@ -186,7 +186,7 @@ abstract class LongPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { + return new Sink.ChainedLong(sink) { @Override public void accept(long t) { downstream.accept((double) t); @@ -208,9 +208,8 @@ abstract class LongPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { + return new Sink.ChainedLong(sink) { @Override - @SuppressWarnings("unchecked") public void accept(long t) { downstream.accept(mapper.applyAsLong(t)); } @@ -226,9 +225,8 @@ abstract class LongPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { + return new Sink.ChainedLong(sink) { @Override - @SuppressWarnings("unchecked") public void accept(long t) { downstream.accept(mapper.apply(t)); } @@ -244,9 +242,8 @@ abstract class LongPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { + return new Sink.ChainedLong(sink) { @Override - @SuppressWarnings("unchecked") public void accept(long t) { downstream.accept(mapper.applyAsInt(t)); } @@ -262,7 +259,7 @@ abstract class LongPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { + return new Sink.ChainedLong(sink) { @Override public void accept(long t) { downstream.accept(mapper.applyAsDouble(t)); @@ -278,7 +275,7 @@ abstract class LongPipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { + return new Sink.ChainedLong(sink) { @Override public void begin(long size) { downstream.begin(-1); @@ -315,7 +312,7 @@ abstract class LongPipeline StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { + return new Sink.ChainedLong(sink) { @Override public void begin(long size) { downstream.begin(-1); @@ -338,7 +335,7 @@ abstract class LongPipeline 0) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { + return new Sink.ChainedLong(sink) { @Override public void accept(long t) { consumer.accept(t); diff --git a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java index c201950d88c..1fffff48b18 100644 --- a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java +++ b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java @@ -163,17 +163,16 @@ abstract class ReferencePipeline StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { @Override public void begin(long size) { downstream.begin(-1); } @Override - @SuppressWarnings("unchecked") public void accept(P_OUT u) { if (predicate.test(u)) - downstream.accept((Object) u); + downstream.accept(u); } }; } @@ -188,7 +187,7 @@ abstract class ReferencePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { @Override public void accept(P_OUT u) { downstream.accept(mapper.apply(u)); @@ -205,7 +204,7 @@ abstract class ReferencePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { @Override public void accept(P_OUT u) { downstream.accept(mapper.applyAsInt(u)); @@ -222,7 +221,7 @@ abstract class ReferencePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { @Override public void accept(P_OUT u) { downstream.accept(mapper.applyAsLong(u)); @@ -239,7 +238,7 @@ abstract class ReferencePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { @Override public void accept(P_OUT u) { downstream.accept(mapper.applyAsDouble(u)); @@ -257,14 +256,13 @@ abstract class ReferencePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { @Override public void begin(long size) { downstream.begin(-1); } @Override - @SuppressWarnings("unchecked") public void accept(P_OUT u) { // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it Stream result = mapper.apply(u); @@ -284,7 +282,7 @@ abstract class ReferencePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { IntConsumer downstreamAsInt = downstream::accept; @Override public void begin(long size) { @@ -311,7 +309,7 @@ abstract class ReferencePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { DoubleConsumer downstreamAsDouble = downstream::accept; @Override public void begin(long size) { @@ -338,7 +336,7 @@ abstract class ReferencePipeline StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { LongConsumer downstreamAsLong = downstream::accept; @Override public void begin(long size) { @@ -364,9 +362,8 @@ abstract class ReferencePipeline 0) { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { @Override - @SuppressWarnings("unchecked") public void accept(P_OUT u) { tee.accept(u); downstream.accept(u); @@ -495,6 +492,7 @@ abstract class ReferencePipeline } @Override + @SuppressWarnings("unchecked") public final R collect(Collector collector) { A container; if (isParallel() diff --git a/jdk/src/share/classes/java/util/stream/Sink.java b/jdk/src/share/classes/java/util/stream/Sink.java index 987d0e9efa7..d2a366df16e 100644 --- a/jdk/src/share/classes/java/util/stream/Sink.java +++ b/jdk/src/share/classes/java/util/stream/Sink.java @@ -241,11 +241,10 @@ interface Sink extends Consumer { * implementation of the {@code accept()} method must call the correct * {@code accept()} method on the downstream {@code Sink}. */ - static abstract class ChainedReference implements Sink { - @SuppressWarnings("rawtypes") - protected final Sink downstream; + static abstract class ChainedReference implements Sink { + protected final Sink downstream; - public ChainedReference(Sink downstream) { + public ChainedReference(Sink downstream) { this.downstream = Objects.requireNonNull(downstream); } @@ -274,11 +273,10 @@ interface Sink extends Consumer { * The implementation of the {@code accept()} method must call the correct * {@code accept()} method on the downstream {@code Sink}. */ - static abstract class ChainedInt implements Sink.OfInt { - @SuppressWarnings("rawtypes") - protected final Sink downstream; + static abstract class ChainedInt implements Sink.OfInt { + protected final Sink downstream; - public ChainedInt(Sink downstream) { + public ChainedInt(Sink downstream) { this.downstream = Objects.requireNonNull(downstream); } @@ -307,11 +305,10 @@ interface Sink extends Consumer { * The implementation of the {@code accept()} method must call the correct * {@code accept()} method on the downstream {@code Sink}. */ - static abstract class ChainedLong implements Sink.OfLong { - @SuppressWarnings("rawtypes") - protected final Sink downstream; + static abstract class ChainedLong implements Sink.OfLong { + protected final Sink downstream; - public ChainedLong(Sink downstream) { + public ChainedLong(Sink downstream) { this.downstream = Objects.requireNonNull(downstream); } @@ -340,11 +337,10 @@ interface Sink extends Consumer { * The implementation of the {@code accept()} method must call the correct * {@code accept()} method on the downstream {@code Sink}. */ - static abstract class ChainedDouble implements Sink.OfDouble { - @SuppressWarnings("rawtypes") - protected final Sink downstream; + static abstract class ChainedDouble implements Sink.OfDouble { + protected final Sink downstream; - public ChainedDouble(Sink downstream) { + public ChainedDouble(Sink downstream) { this.downstream = Objects.requireNonNull(downstream); } diff --git a/jdk/src/share/classes/java/util/stream/SliceOps.java b/jdk/src/share/classes/java/util/stream/SliceOps.java index 09e14f637f4..34d55309d2d 100644 --- a/jdk/src/share/classes/java/util/stream/SliceOps.java +++ b/jdk/src/share/classes/java/util/stream/SliceOps.java @@ -96,6 +96,11 @@ final class SliceOps { } } + @SuppressWarnings("unchecked") + private static IntFunction castingArray() { + return size -> (T[]) new Object[size]; + } + /** * Appends a "slice" operation to the provided stream. The slice operation * may be may be skip-only, limit-only, or skip-and-limit. @@ -107,12 +112,12 @@ final class SliceOps { * is to be imposed */ public static Stream makeRef(AbstractPipeline upstream, - long skip, long limit) { + long skip, long limit) { if (skip < 0) throw new IllegalArgumentException("Skip must be non-negative: " + skip); - return new ReferencePipeline.StatefulOp(upstream, StreamShape.REFERENCE, - flags(limit)) { + return new ReferencePipeline.StatefulOp(upstream, StreamShape.REFERENCE, + flags(limit)) { Spliterator unorderedSkipLimitSpliterator(Spliterator s, long skip, long limit, long sizeIfKnown) { if (skip <= sizeIfKnown) { @@ -146,7 +151,7 @@ final class SliceOps { // cancellation will be more aggressive cancelling later tasks // if the target slice size has been reached from a given task, // cancellation should also clear local results if any - return new SliceTask<>(this, helper, spliterator, i -> (T[]) new Object[i], skip, limit). + return new SliceTask<>(this, helper, spliterator, castingArray(), skip, limit). invoke().spliterator(); } } @@ -182,7 +187,7 @@ final class SliceOps { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedReference(sink) { + return new Sink.ChainedReference(sink) { long n = skip; long m = limit >= 0 ? limit : Long.MAX_VALUE; @@ -291,7 +296,7 @@ final class SliceOps { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedInt(sink) { + return new Sink.ChainedInt(sink) { long n = skip; long m = limit >= 0 ? limit : Long.MAX_VALUE; @@ -400,7 +405,7 @@ final class SliceOps { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedLong(sink) { + return new Sink.ChainedLong(sink) { long n = skip; long m = limit >= 0 ? limit : Long.MAX_VALUE; @@ -509,7 +514,7 @@ final class SliceOps { @Override Sink opWrapSink(int flags, Sink sink) { - return new Sink.ChainedDouble(sink) { + return new Sink.ChainedDouble(sink) { long n = skip; long m = limit >= 0 ? limit : Long.MAX_VALUE; @@ -560,13 +565,13 @@ final class SliceOps { private volatile boolean completed; - SliceTask(AbstractPipeline op, + SliceTask(AbstractPipeline op, PipelineHelper helper, Spliterator spliterator, IntFunction generator, long offset, long size) { super(helper, spliterator); - this.op = (AbstractPipeline) op; + this.op = op; this.generator = generator; this.targetOffset = offset; this.targetSize = size; diff --git a/jdk/src/share/classes/java/util/stream/SortedOps.java b/jdk/src/share/classes/java/util/stream/SortedOps.java index 047479a645d..9df65e352e2 100644 --- a/jdk/src/share/classes/java/util/stream/SortedOps.java +++ b/jdk/src/share/classes/java/util/stream/SortedOps.java @@ -129,7 +129,7 @@ final class SortedOps { } @Override - public Sink opWrapSink(int flags, Sink sink) { + public Sink opWrapSink(int flags, Sink sink) { Objects.requireNonNull(sink); // If the input is already naturally sorted and this operation @@ -280,12 +280,12 @@ final class SortedOps { /** * {@link ForkJoinTask} for implementing sort on SIZED reference streams. */ - private static final class SizedRefSortingSink extends Sink.ChainedReference { + private static final class SizedRefSortingSink extends Sink.ChainedReference { private final Comparator comparator; private T[] array; private int offset; - SizedRefSortingSink(Sink sink, Comparator comparator) { + SizedRefSortingSink(Sink sink, Comparator comparator) { super(sink); this.comparator = comparator; } @@ -320,11 +320,11 @@ final class SortedOps { /** * {@link Sink} for implementing sort on reference streams. */ - private static final class RefSortingSink extends Sink.ChainedReference { + private static final class RefSortingSink extends Sink.ChainedReference { private final Comparator comparator; private ArrayList list; - RefSortingSink(Sink sink, Comparator comparator) { + RefSortingSink(Sink sink, Comparator comparator) { super(sink); this.comparator = comparator; } @@ -352,11 +352,11 @@ final class SortedOps { /** * {@link Sink} for implementing sort on SIZED int streams. */ - private static final class SizedIntSortingSink extends Sink.ChainedInt { + private static final class SizedIntSortingSink extends Sink.ChainedInt { private int[] array; private int offset; - SizedIntSortingSink(Sink downstream) { + SizedIntSortingSink(Sink downstream) { super(downstream); } @@ -386,10 +386,10 @@ final class SortedOps { /** * {@link Sink} for implementing sort on int streams. */ - private static final class IntSortingSink extends Sink.ChainedInt { + private static final class IntSortingSink extends Sink.ChainedInt { private SpinedBuffer.OfInt b; - IntSortingSink(Sink sink) { + IntSortingSink(Sink sink) { super(sink); } @@ -417,11 +417,11 @@ final class SortedOps { /** * {@link Sink} for implementing sort on SIZED long streams. */ - private static final class SizedLongSortingSink extends Sink.ChainedLong { + private static final class SizedLongSortingSink extends Sink.ChainedLong { private long[] array; private int offset; - SizedLongSortingSink(Sink downstream) { + SizedLongSortingSink(Sink downstream) { super(downstream); } @@ -451,10 +451,10 @@ final class SortedOps { /** * {@link Sink} for implementing sort on long streams. */ - private static final class LongSortingSink extends Sink.ChainedLong { + private static final class LongSortingSink extends Sink.ChainedLong { private SpinedBuffer.OfLong b; - LongSortingSink(Sink sink) { + LongSortingSink(Sink sink) { super(sink); } @@ -482,11 +482,11 @@ final class SortedOps { /** * {@link Sink} for implementing sort on SIZED double streams. */ - private static final class SizedDoubleSortingSink extends Sink.ChainedDouble { + private static final class SizedDoubleSortingSink extends Sink.ChainedDouble { private double[] array; private int offset; - SizedDoubleSortingSink(Sink downstream) { + SizedDoubleSortingSink(Sink downstream) { super(downstream); } @@ -516,10 +516,10 @@ final class SortedOps { /** * {@link Sink} for implementing sort on double streams. */ - private static final class DoubleSortingSink extends Sink.ChainedDouble { + private static final class DoubleSortingSink extends Sink.ChainedDouble { private SpinedBuffer.OfDouble b; - DoubleSortingSink(Sink sink) { + DoubleSortingSink(Sink sink) { super(sink); } From 0e8b1016432bdd072bc7c6e24e50e5de88ff32e0 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 21 Aug 2013 09:59:12 +0100 Subject: [PATCH 02/44] 8023351: Add TEST.groups in preparation to simplify rules in jdk/test/Makefile Reviewed-by: lancea, mduigou --- jdk/test/TEST.ROOT | 3 + jdk/test/TEST.groups | 214 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 jdk/test/TEST.groups diff --git a/jdk/test/TEST.ROOT b/jdk/test/TEST.ROOT index 6bf72964f66..0aba9d3bc72 100644 --- a/jdk/test/TEST.ROOT +++ b/jdk/test/TEST.ROOT @@ -9,3 +9,6 @@ othervm.dirs=java/awt java/beans java/rmi javax/accessibility javax/imageio java # Tests that cannot run concurrently exclusiveAccess.dirs=java/rmi/Naming java/util/Currency java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi + +# Group definitions +groups=TEST.groups [closed/TEST.groups] diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups new file mode 100644 index 00000000000..0674bdc1d91 --- /dev/null +++ b/jdk/test/TEST.groups @@ -0,0 +1,214 @@ +# 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. +# + +jdk_lang = \ + java/lang \ + -java/lang/management \ + -java/lang/instrument \ + sun/invoke \ + sun/misc \ + sun/reflect \ + vm + +jdk_util = \ + java/util \ + sun/util + +jdk_math = \ + java/math + +jdk_io = \ + java/io + +jdk_nio = \ + java/nio \ + sun/nio + +jdk_net = \ + java/net \ + com/sun/net \ + com/oracle/net \ + sun/net + +jdk_time = \ + java/time + +jdk_rmi = \ + java/rmi \ + javax/rmi/ssl \ + sun/rmi + +jdk_security1 = \ + java/security + +jdk_security2 = \ + javax/crypto \ + javax/xml/crypto \ + com/sun/crypto + +jdk_security3 = \ + javax/security \ + com/sun/security \ + com/sun/org/apache/xml/internal/security \ + com/oracle/security \ + sun/security \ + lib/security + +jdk_security = \ + :jdk_security1 \ + :jdk_security2 \ + :jdk_security3 + +jdk_text = \ + java/text \ + sun/text + +jdk_management = \ + java/lang/management \ + com/sun/management \ + sun/management + +jdk_instrument = \ + java/lang/instrument + +jdk_jmx = \ + javax/management \ + com/sun/jmx + +jdk_jdi = \ + com/sun/jdi + +# +# Tool (and tool API) tests are split into core and svc groups +# +core_tools = \ + tools \ + com/sun/tools/extcheck \ + sun/tools/java \ + sun/tools/native2ascii \ + sun/tools/jrunscript + +svc_tools = \ + com/sun/tools/attach \ + com/sun/tracing \ + sun/tools \ + -sun/tools/java \ + -sun/tools/native2ascii \ + -sun/tools/jrunscript \ + sun/jvmstat \ + demo/jvmti + +jdk_tools = \ + :core_tools \ + :svc_tools + +# +# Catch-all for other areas with a small number of tests +# +jdk_other = \ + java/sql \ + javax/sql \ + javax/naming \ + javax/script \ + javax/smartcardio \ + javax/xml \ + -javax/xml/crypto \ + jdk/asm \ + jdk/lambda \ + com/sun/jndi \ + com/sun/corba \ + lib/testlibrary \ + demo/zipfs \ + sample + +# +# SCTP is its own group as it is highly sensitive to kernel/network config +# +jdk_sctp = \ + com/sun/nio/sctp + + +# +# core group to run all core area tests +# +jdk_core = \ + :jdk_lang \ + :jdk_util \ + :jdk_math \ + :jdk_io \ + :jdk_nio \ + :jdk_net \ + :jdk_rmi \ + :jdk_time \ + :jdk_security \ + :jdk_text \ + :core_tools \ + :jdk_other + +# +# svc group to run all serviceability area tests +# +jdk_svc = \ + :jdk_management \ + :jdk_instrument \ + :jdk_jmx \ + :jdk_jdi \ + :svc_tools + +############################# + +# +# Client area groups +# + +jdk_awt = \ + java/awt \ + com/sun/awt \ + com/apple/eawt \ + sun/awt + +jdk_2d = \ + javax/print \ + sun/pisces \ + sun/java2d + +jdk_beans = \ + java/beans + +jdk_swing = \ + javax/accessibility \ + javax/swing \ + com/sun/java/swing + +jdk_sound = \ + javax/sound + +jdk_imageio = \ + javax/imageio + +jdk_desktop = \ + :jdk_awt \ + :jdk_2d \ + :jdk_beans \ + :jdk_swing \ + :jdk_sound \ + :jdk_imageio From bf1e11707b5305407f23099bd5bf07beed50a742 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 19 Aug 2013 12:57:17 +0200 Subject: [PATCH 03/44] 6358357: Division by zero in Threads tab when shrinking jconsole window Reviewed-by: mchung, leifs, jbachorik --- jdk/src/share/classes/sun/tools/jconsole/Plotter.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/tools/jconsole/Plotter.java b/jdk/src/share/classes/sun/tools/jconsole/Plotter.java index 793b0ea263d..acfd005dd0b 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/Plotter.java +++ b/jdk/src/share/classes/sun/tools/jconsole/Plotter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -337,6 +337,13 @@ public class Plotter extends JComponent public void paintComponent(Graphics g) { super.paintComponent(g); + int width = getWidth()-rightMargin-leftMargin-10; + int height = getHeight()-topMargin-bottomMargin; + if (width <= 0 || height <= 0) { + // not enough room to paint anything + return; + } + Color oldColor = g.getColor(); Font oldFont = g.getFont(); Color fg = getForeground(); From 99f960f2ef451260691e4a0ccbf57f28bdc28395 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 19 Aug 2013 16:21:49 +0200 Subject: [PATCH 04/44] 6417721: Thread list should not allow multiple selection Reviewed-by: alanb, jbachorik, sjiang --- jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java b/jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java index 354f351f750..3932ffa145e 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java +++ b/jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java @@ -595,6 +595,7 @@ class ThreadTab extends Tab implements ActionListener, DocumentListener, ListSel setBorder(thinEmptyBorder); + setSelectionMode(ListSelectionModel.SINGLE_SELECTION); addListSelectionListener(ThreadTab.this); setCellRenderer(new DefaultListCellRenderer() { public Component getListCellRendererComponent(JList list, Object value, int index, From 1d3c8aa7088a6c323b34f78644e48d56843e625f Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 19 Aug 2013 16:41:21 +0200 Subject: [PATCH 05/44] 6800801: NPE in JConsole when using Nimbus L&F Reviewed-by: alanb, sjiang --- .../share/classes/sun/tools/jconsole/ConnectDialog.java | 9 +++++++-- jdk/src/share/classes/sun/tools/jconsole/VMPanel.java | 8 +++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/jdk/src/share/classes/sun/tools/jconsole/ConnectDialog.java b/jdk/src/share/classes/sun/tools/jconsole/ConnectDialog.java index ea3f8366766..3198fd6cd6a 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/ConnectDialog.java +++ b/jdk/src/share/classes/sun/tools/jconsole/ConnectDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -268,8 +268,13 @@ public class ConnectDialog extends InternalDialog public void revalidate() { // Adjust some colors + Color disabledForeground = UIManager.getColor("Label.disabledForeground"); + if (disabledForeground == null) { + // fall back for Nimbus that doesn't support 'Label.disabledForeground' + disabledForeground = UIManager.getColor("Label.disabledText"); + } hintTextColor = - ensureContrast(UIManager.getColor("Label.disabledForeground"), + ensureContrast(disabledForeground, UIManager.getColor("Panel.background")); disabledTableCellColor = ensureContrast(new Color(0x808080), diff --git a/jdk/src/share/classes/sun/tools/jconsole/VMPanel.java b/jdk/src/share/classes/sun/tools/jconsole/VMPanel.java index b7a0f5b410b..1561b9cc5bb 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/VMPanel.java +++ b/jdk/src/share/classes/sun/tools/jconsole/VMPanel.java @@ -153,9 +153,11 @@ public class VMPanel extends JTabbedPane implements PropertyChangeListener { // in order to reserve space for the connect toggle. public void setUI(TabbedPaneUI ui) { Insets insets = (Insets) UIManager.getLookAndFeelDefaults().get("TabbedPane.tabAreaInsets"); - insets = (Insets) insets.clone(); - insets.right += connectedIcon24.getIconWidth() + 8; - UIManager.put("TabbedPane.tabAreaInsets", insets); + if (insets != null) { + insets = (Insets) insets.clone(); + insets.right += connectedIcon24.getIconWidth() + 8; + UIManager.put("TabbedPane.tabAreaInsets", insets); + } super.setUI(ui); } From 910c4e1d3467206e2bf8696124018fd20adc64a7 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 19 Aug 2013 13:11:03 +0200 Subject: [PATCH 06/44] 7042707: Un-needed mnemonic in JConsole resource file Reviewed-by: mfang, jbachorik --- jdk/src/share/classes/sun/tools/jconsole/Messages.java | 3 +-- .../classes/sun/tools/jconsole/resources/messages.properties | 1 - .../sun/tools/jconsole/resources/messages_ja.properties | 1 - .../sun/tools/jconsole/resources/messages_zh_CN.properties | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/jdk/src/share/classes/sun/tools/jconsole/Messages.java b/jdk/src/share/classes/sun/tools/jconsole/Messages.java index 0e5fd76bd20..eee57adcc25 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/Messages.java +++ b/jdk/src/share/classes/sun/tools/jconsole/Messages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -146,7 +146,6 @@ final public class Messages { public static String HELP_ABOUT_DIALOG_MASTHEAD_ACCESSIBLE_NAME; public static String HELP_ABOUT_DIALOG_MASTHEAD_TITLE; public static String HELP_ABOUT_DIALOG_TITLE; - public static String HELP_ABOUT_DIALOG_USER_GUIDE_LINK; public static String HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL; public static String HELP_MENU_ABOUT_TITLE; public static String HELP_MENU_USER_GUIDE_TITLE; diff --git a/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties b/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties index ef0b4f136e4..70ff2f16c6e 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties +++ b/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties @@ -104,7 +104,6 @@ HELP_ABOUT_DIALOG_JAVA_VERSION=Java VM version:
{0} HELP_ABOUT_DIALOG_MASTHEAD_ACCESSIBLE_NAME=Masthead Graphic HELP_ABOUT_DIALOG_MASTHEAD_TITLE=About JConsole HELP_ABOUT_DIALOG_TITLE=JConsole: About -HELP_ABOUT_DIALOG_USER_GUIDE_LINK=JConsole &User Guide:
{0} HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://docs.oracle.com/javase/{0}/docs/technotes/guides/management/jconsole.html HELP_MENU_ABOUT_TITLE=&About JConsole HELP_MENU_USER_GUIDE_TITLE=Online &User Guide diff --git a/jdk/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties b/jdk/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties index 9cc5df8fad8..c66ace77035 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties +++ b/jdk/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties @@ -104,7 +104,6 @@ HELP_ABOUT_DIALOG_JAVA_VERSION=Java VM\u30D0\u30FC\u30B8\u30E7\u30F3:
{0} HELP_ABOUT_DIALOG_MASTHEAD_ACCESSIBLE_NAME=\u30DE\u30B9\u30C8\u30D8\u30C3\u30C9\u56F3\u5F62 HELP_ABOUT_DIALOG_MASTHEAD_TITLE=JConsole\u306B\u3064\u3044\u3066 HELP_ABOUT_DIALOG_TITLE=JConsole: \u8A73\u7D30 -HELP_ABOUT_DIALOG_USER_GUIDE_LINK=JConsole\u30E6\u30FC\u30B6\u30FC\u30FB\u30AC\u30A4\u30C9(&U):
{0} HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://docs.oracle.com/javase/{0}/docs/technotes/guides/management/jconsole.html HELP_MENU_ABOUT_TITLE=JConsole\u306B\u3064\u3044\u3066(&A) HELP_MENU_USER_GUIDE_TITLE=\u30AA\u30F3\u30E9\u30A4\u30F3\u30FB\u30E6\u30FC\u30B6\u30FC\u30FB\u30AC\u30A4\u30C9(&U) diff --git a/jdk/src/share/classes/sun/tools/jconsole/resources/messages_zh_CN.properties b/jdk/src/share/classes/sun/tools/jconsole/resources/messages_zh_CN.properties index d654392edf2..3f782adc620 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/resources/messages_zh_CN.properties +++ b/jdk/src/share/classes/sun/tools/jconsole/resources/messages_zh_CN.properties @@ -104,7 +104,6 @@ HELP_ABOUT_DIALOG_JAVA_VERSION=Java VM \u7248\u672C:
{0} HELP_ABOUT_DIALOG_MASTHEAD_ACCESSIBLE_NAME=\u62A5\u5934\u56FE HELP_ABOUT_DIALOG_MASTHEAD_TITLE=\u5173\u4E8E JConsole HELP_ABOUT_DIALOG_TITLE=JConsole: \u5173\u4E8E -HELP_ABOUT_DIALOG_USER_GUIDE_LINK=JConsole \u7528\u6237\u6307\u5357(&U):
{0} HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://docs.oracle.com/javase/{0}/docs/technotes/guides/management/jconsole.html HELP_MENU_ABOUT_TITLE=\u5173\u4E8E JConsole(&A) HELP_MENU_USER_GUIDE_TITLE=\u8054\u673A\u7528\u6237\u6307\u5357(&U) From 7568ce74817aebe1d62d0bb86e9b560d0674a68c Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 21 Aug 2013 05:56:46 -0400 Subject: [PATCH 07/44] 8023460: OPENJDK build fails due to missing jfr.jar Reviewed-by: alanb --- jdk/makefiles/Profiles.gmk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jdk/makefiles/Profiles.gmk b/jdk/makefiles/Profiles.gmk index 47fadcc9df9..9e79b2b27ac 100644 --- a/jdk/makefiles/Profiles.gmk +++ b/jdk/makefiles/Profiles.gmk @@ -65,10 +65,6 @@ PROFILE_2_JARS := \ $(if $(PROFILE_2_JRE_JAR_FILES), $(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_2_JRE_JAR_FILES))) \ $(PROFILE_1_JARS) -ifneq ($(ENABLE_JFR), true) - PROFILE_3_JRE_JAR_FILES := $(filter-out jfr.jar, $(PROFILE_3_JRE_JAR_FILES)) -endif - PROFILE_3_JARS := \ $(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_3_JRE_JAR_FILES)) \ $(PROFILE_2_JARS) @@ -77,6 +73,10 @@ ifdef OPENJDK FULL_JRE_JAR_FILES := $(filter-out alt-rt.jar, $(FULL_JRE_JAR_FILES)) endif +ifneq ($(ENABLE_JFR), true) + FULL_JRE_JAR_FILES := $(filter-out jfr.jar, $(FULL_JRE_JAR_FILES)) +endif + FULL_JRE_JARS := \ $(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(FULL_JRE_JAR_FILES)) \ $(PROFILE_3_JARS) From 01ba926ba1c9bb8bf32f017a74d1c2549b866bce Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Wed, 21 Aug 2013 17:19:46 +0200 Subject: [PATCH 08/44] 8023485: Remove com/sun/jdi/DoubleAgentTest.java and com/sun/jdi/FieldWatchpoints.java from ProblemList.txt Reviewed-by: chegar, mgronlun --- jdk/test/ProblemList.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 00a354a7b0d..ab2eac5ecbd 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -336,12 +336,6 @@ com/sun/jdi/SuspendThreadTest.java generic-all # Filed 6653793 com/sun/jdi/RedefineCrossEvent.java generic-all -# Filed 6987312 -com/sun/jdi/DoubleAgentTest.java generic-all - -# Filed 7020857 -com/sun/jdi/FieldWatchpoints.java generic-all - # Filed 6402201 com/sun/jdi/ProcessAttachTest.sh generic-all From 8a3c65febe4da5102c544676429e26868e6110ee Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Wed, 21 Aug 2013 12:03:19 -0700 Subject: [PATCH 09/44] 8023306: Add replace() implementations to TreeMap Reviewed-by: psandoz, alanb, chegar, bpb --- jdk/src/share/classes/java/util/TreeMap.java | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/jdk/src/share/classes/java/util/TreeMap.java b/jdk/src/share/classes/java/util/TreeMap.java index 52d9df25a0b..9a4681d771a 100644 --- a/jdk/src/share/classes/java/util/TreeMap.java +++ b/jdk/src/share/classes/java/util/TreeMap.java @@ -972,6 +972,27 @@ public class TreeMap return tailMap(fromKey, true); } + @Override + public boolean replace(K key, V oldValue, V newValue) { + Entry p = getEntry(key); + if (p!=null && Objects.equals(oldValue, p.value)) { + p.value = newValue; + return true; + } + return false; + } + + @Override + public V replace(K key, V value) { + Entry p = getEntry(key); + if (p!=null) { + V oldValue = p.value; + p.value = value; + return oldValue; + } + return null; + } + @Override public void forEach(BiConsumer action) { Objects.requireNonNull(action); From 629de57fe861fa4cfc986f48570c17790381e0b5 Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Wed, 21 Aug 2013 12:03:28 -0700 Subject: [PATCH 10/44] 8023395: Remove sun.misc.Sort and sun.misc.Compare Reviewed-by: alanb, smarks, darcy, mr --- jdk/src/share/classes/sun/misc/Compare.java | 46 ------------- jdk/src/share/classes/sun/misc/Sort.java | 74 --------------------- 2 files changed, 120 deletions(-) delete mode 100644 jdk/src/share/classes/sun/misc/Compare.java delete mode 100644 jdk/src/share/classes/sun/misc/Sort.java diff --git a/jdk/src/share/classes/sun/misc/Compare.java b/jdk/src/share/classes/sun/misc/Compare.java deleted file mode 100644 index 400fc1713ca..00000000000 --- a/jdk/src/share/classes/sun/misc/Compare.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 1996, 1997, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * Compare: an interface to enable users to define the result of - * a comparison of two objects. - * - * @author Sunita Mani - */ - -package sun.misc; - -public interface Compare { - - /** - * doCompare - * - * @param obj1 first object to compare. - * @param obj2 second object to compare. - * @return -1 if obj1 < obj2, 0 if obj1 == obj2, 1 if obj1 > obj2. - */ - public int doCompare(Object obj1, Object obj2); - -} diff --git a/jdk/src/share/classes/sun/misc/Sort.java b/jdk/src/share/classes/sun/misc/Sort.java deleted file mode 100644 index adf8e78ff2c..00000000000 --- a/jdk/src/share/classes/sun/misc/Sort.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * Sort: a class that uses the quicksort algorithm to sort an - * array of objects. - * - * @author Sunita Mani - */ - -package sun.misc; - -public class Sort { - - private static void swap(Object arr[], int i, int j) { - Object tmp; - - tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } - - /** - * quicksort the array of objects. - * - * @param arr[] - an array of objects - * @param left - the start index - from where to begin sorting - * @param right - the last index. - * @param comp - an object that implemnts the Compare interface to resolve thecomparison. - */ - public static void quicksort(Object arr[], int left, int right, Compare comp) { - int i, last; - - if (left >= right) { /* do nothing if array contains fewer than two */ - return; /* two elements */ - } - swap(arr, left, (left+right) / 2); - last = left; - for (i = left+1; i <= right; i++) { - if (comp.doCompare(arr[i], arr[left]) < 0) { - swap(arr, ++last, i); - } - } - swap(arr, left, last); - quicksort(arr, left, last-1, comp); - quicksort(arr, last+1, right, comp); - } - - public static void quicksort(Object arr[], Compare comp) { - quicksort(arr, 0, arr.length-1, comp); - } -} From c9443a8346bb73891c3cdbc7e174daebf4fa1b79 Mon Sep 17 00:00:00 2001 From: Ben Evans Date: Tue, 20 Aug 2013 14:23:32 -0700 Subject: [PATCH 11/44] 8016846: Pattern.splitAsStream tests required Reviewed-by: alanb, psandoz --- jdk/test/java/util/regex/PatternTest.java | 147 ++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 jdk/test/java/util/regex/PatternTest.java diff --git a/jdk/test/java/util/regex/PatternTest.java b/jdk/test/java/util/regex/PatternTest.java new file mode 100644 index 00000000000..aab17319ae4 --- /dev/null +++ b/jdk/test/java/util/regex/PatternTest.java @@ -0,0 +1,147 @@ +/* + * 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 + * @summary Unit tests for wrapping classes should delegate to default methods + * @library ../stream/bootlib + * @build java.util.stream.OpTestCase + * @run testng/othervm PatternTest + */ + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; +import java.util.regex.Pattern; +import java.util.stream.LambdaTestHelpers; +import java.util.stream.OpTestCase; +import java.util.stream.Stream; +import java.util.stream.TestData; + +@Test +public class PatternTest extends OpTestCase { + + @DataProvider(name = "Stream") + public static Object[][] makeStreamTestData() { + List data = new ArrayList<>(); + + String description = ""; + String input = "awgqwefg1fefw4vssv1vvv1"; + Pattern pattern = Pattern.compile("4"); + List expected = new ArrayList<>(); + expected.add("awgqwefg1fefw"); + expected.add("vssv1vvv1"); + + // Must match the type signature of the consumer of this data, testStrings + // String, String, Pattern, List + data.add(new Object[]{description, input, pattern, expected}); + + input = "afbfq\u00a3abgwgb\u00a3awngnwggw\u00a3a\u00a3ahjrnhneerh"; + pattern = Pattern.compile("\u00a3a"); + expected = new ArrayList<>(); + expected.add("afbfq"); + expected.add("bgwgb"); + expected.add("wngnwggw"); + expected.add(""); + expected.add("hjrnhneerh"); + + data.add(new Object[]{description, input, pattern, expected}); + + + input = "awgqwefg1fefw4vssv1vvv1"; + pattern = Pattern.compile("1"); + expected = new ArrayList<>(); + expected.add("awgqwefg"); + expected.add("fefw4vssv"); + expected.add("vvv"); + + data.add(new Object[]{description, input, pattern, expected}); + + + input = "a\u4ebafg1fefw\u4eba4\u9f9cvssv\u9f9c1v\u672c\u672cvv"; + pattern = Pattern.compile("1"); + expected = new ArrayList<>(); + expected.add("a\u4ebafg"); + expected.add("fefw\u4eba4\u9f9cvssv\u9f9c"); + expected.add("v\u672c\u672cvv"); + + data.add(new Object[]{description, input, pattern, expected}); + + + input = "1\u56da23\u56da456\u56da7890"; + pattern = Pattern.compile("\u56da"); + expected = new ArrayList<>(); + expected.add("1"); + expected.add("23"); + expected.add("456"); + expected.add("7890"); + + data.add(new Object[]{description, input, pattern, expected}); + + + input = "1\u56da23\u9f9c\u672c\u672c\u56da456\u56da\u9f9c\u672c7890"; + pattern = Pattern.compile("\u56da"); + expected = new ArrayList<>(); + expected.add("1"); + expected.add("23\u9f9c\u672c\u672c"); + expected.add("456"); + expected.add("\u9f9c\u672c7890"); + + data.add(new Object[]{description, input, pattern, expected}); + + + input = ""; + pattern = Pattern.compile("\u56da"); + expected = new ArrayList<>(); + + data.add(new Object[]{description, input, pattern, expected}); + + + description = "Multiple separators"; + input = "This is,testing: with\tdifferent separators."; + pattern = Pattern.compile("[ \t,:.]"); + expected = new ArrayList<>(); + expected.add("This"); + expected.add("is"); + expected.add("testing"); + expected.add(""); + expected.add("with"); + expected.add("different"); + expected.add("separators"); + + data.add(new Object[] {description, input, pattern, expected}); + return data.toArray(new Object[0][]); + } + + @Test(dataProvider = "Stream") + public void testStrings(String description, String input, Pattern pattern, List expected) { + Supplier> ss = () -> pattern.splitAsStream(input); + withData(TestData.Factory.ofSupplier(description, ss)) + .stream(LambdaTestHelpers.identity()) + .expectedResult(expected) + .exercise(); + } +} From cac8b88f4892dd356e2612a51c8045810ed1fc06 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Wed, 21 Aug 2013 19:44:35 -0700 Subject: [PATCH 12/44] 8022228: Intermittent test failures in sun/security/ssl/javax/net/ssl/NewAPIs Reviewed-by: weijun --- .../ssl/NewAPIs/SessionCacheSizeTests.java | 124 +++++++++++++----- .../net/ssl/NewAPIs/SessionTimeOutTests.java | 119 ++++++++++++----- .../ssl/templates/SSLSocketTemplate.java | 2 +- 3 files changed, 176 insertions(+), 69 deletions(-) diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SessionCacheSizeTests.java b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SessionCacheSizeTests.java index d5fdadd9b1e..d4e00855dc6 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SessionCacheSizeTests.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SessionCacheSizeTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -21,14 +21,16 @@ * questions. */ +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + /* * @test * @bug 4366807 * @summary Need new APIs to get/set session timeout and session cache size. * @run main/othervm SessionCacheSizeTests - * - * SunJSSE does not support dynamic system properties, no way to re-use - * system properties in samevm/agentvm mode. */ import java.io.*; @@ -113,7 +115,9 @@ public class SessionCacheSizeTests { /* * Signal Client, we're ready for his connect. */ - serverReady = true; + if (createdPorts == serverPorts.length) { + serverReady = true; + } int read = 0; int nConnections = 0; /* @@ -310,7 +314,6 @@ public class SessionCacheSizeTests { * Fork off the other side, then do your work. */ SessionCacheSizeTests() throws Exception { - /* * create the SSLServerSocket and SSLSocket factories */ @@ -323,46 +326,87 @@ public class SessionCacheSizeTests { int serverConns = MAX_ACTIVE_CONNECTIONS / (serverPorts.length); int remainingConns = MAX_ACTIVE_CONNECTIONS % (serverPorts.length); - if (separateServerThread) { - for (int i = 0; i < serverPorts.length; i++) { - - // distribute remaining connections among the available ports - if (i < remainingConns) - startServer(serverPorts[i], (serverConns + 1), true); - else - startServer(serverPorts[i], serverConns, true); - } - startClient(false); - } else { - startClient(true); - for (int i = 0; i < serverPorts.length; i++) { - if (i < remainingConns) - startServer(serverPorts[i], (serverConns + 1), false); - else - startServer(serverPorts[i], serverConns, false); + Exception startException = null; + try { + if (separateServerThread) { + for (int i = 0; i < serverPorts.length; i++) { + // distribute remaining connections among the + // available ports + if (i < remainingConns) + startServer(serverPorts[i], (serverConns + 1), true); + else + startServer(serverPorts[i], serverConns, true); + } + startClient(false); + } else { + startClient(true); + for (int i = 0; i < serverPorts.length; i++) { + if (i < remainingConns) + startServer(serverPorts[i], (serverConns + 1), false); + else + startServer(serverPorts[i], serverConns, false); + } } + } catch (Exception e) { + startException = e; } /* * Wait for other side to close down. */ if (separateServerThread) { - serverThread.join(); + if (serverThread != null) { + serverThread.join(); + } } else { - clientThread.join(); + if (clientThread != null) { + clientThread.join(); + } } /* * When we get here, the test is pretty much over. - * - * If the main thread excepted, that propagates back - * immediately. If the other thread threw an exception, we - * should report back. */ - if (serverException != null) - throw serverException; - if (clientException != null) - throw clientException; + Exception local; + Exception remote; + + if (separateServerThread) { + remote = serverException; + local = clientException; + } else { + remote = clientException; + local = serverException; + } + + Exception exception = null; + + /* + * Check various exception conditions. + */ + if ((local != null) && (remote != null)) { + // If both failed, return the curthread's exception. + local.initCause(remote); + exception = local; + } else if (local != null) { + exception = local; + } else if (remote != null) { + exception = remote; + } else if (startException != null) { + exception = startException; + } + + /* + * If there was an exception *AND* a startException, + * output it. + */ + if (exception != null) { + if (exception != startException && startException != null) { + exception.addSuppressed(startException); + } + throw exception; + } + + // Fall-through: no exception to throw! } void startServer(final int port, final int nConns, @@ -387,7 +431,13 @@ public class SessionCacheSizeTests { }; serverThread.start(); } else { - doServerSide(port, nConns); + try { + doServerSide(port, nConns); + } catch (Exception e) { + serverException = e; + } finally { + serverReady = true; + } } } @@ -409,7 +459,11 @@ public class SessionCacheSizeTests { }; clientThread.start(); } else { - doClientSide(); + try { + doClientSide(); + } catch (Exception e) { + clientException = e; + } } } } diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SessionTimeOutTests.java b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SessionTimeOutTests.java index 3d0946724f5..9264cb08723 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SessionTimeOutTests.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SessionTimeOutTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -21,14 +21,14 @@ * questions. */ +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. + /* * @test * @bug 4366807 * @summary Need new APIs to get/set session timeout and session cache size. * @run main/othervm SessionTimeOutTests - * - * SunJSSE does not support dynamic system properties, no way to re-use - * system properties in samevm/agentvm mode. */ import java.io.*; @@ -263,7 +263,7 @@ public class SessionTimeOutTests { for (int i = 0; i < nConnections; i++) { sslSockets[i].close(); } - System.out.println("----------------------------------------" + System.out.println("----------------------------------------" + "-----------------------"); System.out.println("Session timeout test passed"); } @@ -348,45 +348,88 @@ public class SessionTimeOutTests { int serverConns = MAX_ACTIVE_CONNECTIONS / (serverPorts.length); int remainingConns = MAX_ACTIVE_CONNECTIONS % (serverPorts.length); - if (separateServerThread) { - for (int i = 0; i < serverPorts.length; i++) { - // distribute remaining connections among the available ports - if (i < remainingConns) - startServer(serverPorts[i], (serverConns + 1), true); - else - startServer(serverPorts[i], serverConns, true); - } - startClient(false); - } else { - startClient(true); - for (int i = 0; i < serverPorts.length; i++) { - if (i < remainingConns) - startServer(serverPorts[i], (serverConns + 1), false); - else - startServer(serverPorts[i], serverConns, false); + Exception startException = null; + try { + if (separateServerThread) { + for (int i = 0; i < serverPorts.length; i++) { + // distribute remaining connections among the + // vailable ports + if (i < remainingConns) + startServer(serverPorts[i], (serverConns + 1), true); + else + startServer(serverPorts[i], serverConns, true); + } + startClient(false); + } else { + startClient(true); + for (int i = 0; i < serverPorts.length; i++) { + if (i < remainingConns) + startServer(serverPorts[i], (serverConns + 1), false); + else + startServer(serverPorts[i], serverConns, false); + } } + } catch (Exception e) { + startException = e; } /* * Wait for other side to close down. */ if (separateServerThread) { - serverThread.join(); + if (serverThread != null) { + serverThread.join(); + } } else { - clientThread.join(); + if (clientThread != null) { + clientThread.join(); + } } /* * When we get here, the test is pretty much over. - * - * If the main thread excepted, that propagates back - * immediately. If the other thread threw an exception, we - * should report back. + * Which side threw the error? */ - if (serverException != null) - throw serverException; - if (clientException != null) - throw clientException; + Exception local; + Exception remote; + + if (separateServerThread) { + remote = serverException; + local = clientException; + } else { + remote = clientException; + local = serverException; + } + + Exception exception = null; + + /* + * Check various exception conditions. + */ + if ((local != null) && (remote != null)) { + // If both failed, return the curthread's exception. + local.initCause(remote); + exception = local; + } else if (local != null) { + exception = local; + } else if (remote != null) { + exception = remote; + } else if (startException != null) { + exception = startException; + } + + /* + * If there was an exception *AND* a startException, + * output it. + */ + if (exception != null) { + if (exception != startException && startException != null) { + exception.addSuppressed(startException); + } + throw exception; + } + + // Fall-through: no exception to throw! } void startServer(final int port, final int nConns, @@ -411,7 +454,13 @@ public class SessionTimeOutTests { }; serverThread.start(); } else { - doServerSide(port, nConns); + try { + doServerSide(port, nConns); + } catch (Exception e) { + serverException = e; + } finally { + serverReady = 0; + } } } @@ -433,7 +482,11 @@ public class SessionTimeOutTests { }; clientThread.start(); } else { - doClientSide(); + try { + doClientSide(); + } catch (Exception e) { + clientException = e; + } } } } diff --git a/jdk/test/sun/security/ssl/templates/SSLSocketTemplate.java b/jdk/test/sun/security/ssl/templates/SSLSocketTemplate.java index e8bfe91db06..af9f40f77c5 100644 --- a/jdk/test/sun/security/ssl/templates/SSLSocketTemplate.java +++ b/jdk/test/sun/security/ssl/templates/SSLSocketTemplate.java @@ -243,7 +243,7 @@ public class SSLSocketTemplate { * output it. */ if (exception != null) { - if (exception != startException) { + if (exception != startException && startException != null) { exception.addSuppressed(startException); } throw exception; From 138561d596308e0126916afcd65427d218fcfe3f Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Thu, 22 Aug 2013 08:28:53 +0200 Subject: [PATCH 13/44] 8023101: java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java fails Reviewed-by: ysr --- .../management/MemoryMXBean/ResetPeakMemoryUsage.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jdk/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java b/jdk/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java index 9e37d6670f4..1cc530e6541 100644 --- a/jdk/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java +++ b/jdk/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java @@ -33,10 +33,10 @@ * @author Mandy Chung * * @build ResetPeakMemoryUsage MemoryUtil - * @run main/othervm -XX:+UseSerialGC -XX:MarkSweepAlwaysCompactCount=1 -Xmn8m ResetPeakMemoryUsage - * @run main/othervm -XX:+UseConcMarkSweepGC -Xmn8m ResetPeakMemoryUsage - * @run main/othervm -XX:+UseParallelGC -Xmn8m ResetPeakMemoryUsage - * @run main/othervm -XX:+UseG1GC -Xmn8m -XX:G1HeapRegionSize=1m ResetPeakMemoryUsage + * @run main/othervm -XX:+PrintGCDetails -XX:+UseSerialGC -Xms256m -XX:MarkSweepAlwaysCompactCount=1 -Xmn8m ResetPeakMemoryUsage + * @run main/othervm -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC -Xms256m -Xmn8m ResetPeakMemoryUsage + * @run main/othervm -XX:+PrintGCDetails -XX:+UseParallelGC -Xms256m -Xmn8m ResetPeakMemoryUsage + * @run main/othervm -XX:+PrintGCDetails -XX:+UseG1GC -Xms256m -Xmn8m -XX:G1HeapRegionSize=1m ResetPeakMemoryUsage */ import java.lang.management.*; From b3961cb6be42c942bc00dd1332a99c15ef43a4c5 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 22 Aug 2013 09:40:36 -0700 Subject: [PATCH 14/44] 8023587: Fix lone remaining doclint issue in java.util.regex Reviewed-by: jjg --- jdk/src/share/classes/java/util/regex/Pattern.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/util/regex/Pattern.java b/jdk/src/share/classes/java/util/regex/Pattern.java index d7b800e3258..4eedd34c72a 100644 --- a/jdk/src/share/classes/java/util/regex/Pattern.java +++ b/jdk/src/share/classes/java/util/regex/Pattern.java @@ -219,7 +219,7 @@ import java.util.stream.StreamSupport; * *   * Classes for Unicode scripts, blocks, categories and binary properties - * * {@code \p{IsLatin}} + * {@code \p{IsLatin}} * A Latin script character (
script) * {@code \p{InGreek}} * A character in the Greek block (block) From 31584b6b19d1565c35d0ce4fe4fb2adc3b92f533 Mon Sep 17 00:00:00 2001 From: Dan Xu Date: Thu, 22 Aug 2013 11:43:18 -0700 Subject: [PATCH 15/44] 8023430: Replace File.mkdirs with Files.createDirectories to get MaxPathLength.java failure details Reviewed-by: alanb --- jdk/test/ProblemList.txt | 2 +- jdk/test/java/io/File/MaxPathLength.java | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index ab2eac5ecbd..1f594fe3d3b 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -208,7 +208,7 @@ sun/net/www/http/HttpClient/ProxyTest.java generic-all # jdk_io # 7160013 -java/io/File/MaxPathLength.java windows-all +#java/io/File/MaxPathLength.java windows-all ############################################################################ diff --git a/jdk/test/java/io/File/MaxPathLength.java b/jdk/test/java/io/File/MaxPathLength.java index 4111550bbd2..7ec379cf1d1 100644 --- a/jdk/test/java/io/File/MaxPathLength.java +++ b/jdk/test/java/io/File/MaxPathLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -27,6 +27,7 @@ */ import java.io.*; +import java.nio.file.Files; public class MaxPathLength { private static String sep = File.separator; @@ -87,10 +88,8 @@ public class MaxPathLength { System.err.println("Warning: Test directory structure exists already!"); return; } - boolean couldMakeTestDirectory = dirFile.mkdirs(); - if (!couldMakeTestDirectory) { - throw new RuntimeException ("Could not create test directory structure"); - } + Files.createDirectories(dirFile.toPath()); + try { if (tryAbsolute) dirFile = new File(dirFile.getCanonicalPath()); From 75a8f58cd15ecb61864255a403935cfe5e4305c8 Mon Sep 17 00:00:00 2001 From: Peter Levart Date: Tue, 20 Aug 2013 14:13:59 +0200 Subject: [PATCH 16/44] 8022721: AnnotationTypeDeadlockTest.java throws java.lang.IllegalStateException: unexpected condition Reviewed-by: alanb, jfranck --- .../AnnotationTypeDeadlockTest.java | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/jdk/test/java/lang/annotation/AnnotationType/AnnotationTypeDeadlockTest.java b/jdk/test/java/lang/annotation/AnnotationType/AnnotationTypeDeadlockTest.java index 65d171adf43..f60c33525a8 100644 --- a/jdk/test/java/lang/annotation/AnnotationType/AnnotationTypeDeadlockTest.java +++ b/jdk/test/java/lang/annotation/AnnotationType/AnnotationTypeDeadlockTest.java @@ -28,6 +28,9 @@ */ import java.lang.annotation.Retention; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; @@ -66,17 +69,6 @@ public class AnnotationTypeDeadlockTest { } } - static void dumpState(Task task) { - System.err.println( - "Task[" + task.getName() + "].state: " + - task.getState() + " ..." - ); - for (StackTraceElement ste : task.getStackTrace()) { - System.err.println("\tat " + ste); - } - System.err.println(); - } - public static void main(String[] args) throws Exception { CountDownLatch prepareLatch = new CountDownLatch(2); AtomicInteger goLatch = new AtomicInteger(1); @@ -88,18 +80,22 @@ public class AnnotationTypeDeadlockTest { prepareLatch.await(); // let them go goLatch.set(0); - // attempt to join them - taskA.join(5000L); - taskB.join(5000L); - - if (taskA.isAlive() || taskB.isAlive()) { - dumpState(taskA); - dumpState(taskB); - throw new IllegalStateException( - taskA.getState() == Thread.State.BLOCKED && - taskB.getState() == Thread.State.BLOCKED - ? "deadlock detected" - : "unexpected condition"); + // obtain ThreadMXBean + ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); + // wait for threads to finish or dead-lock + while (taskA.isAlive() || taskB.isAlive()) { + // attempt to join threads + taskA.join(500L); + taskB.join(500L); + // detect dead-lock + long[] deadlockedIds = threadBean.findMonitorDeadlockedThreads(); + if (deadlockedIds != null && deadlockedIds.length > 0) { + StringBuilder sb = new StringBuilder("deadlock detected:\n\n"); + for (ThreadInfo ti : threadBean.getThreadInfo(deadlockedIds, Integer.MAX_VALUE)) { + sb.append(ti); + } + throw new IllegalStateException(sb.toString()); + } } } } From edd19c0f397d2a86a19899074dc3ff0bea88d602 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Thu, 22 Aug 2013 15:54:50 -0700 Subject: [PATCH 17/44] 8022445: fix RMISocketFactory example to avoid using localhost Reviewed-by: chegar, alanb --- .../share/classes/java/rmi/server/RMISocketFactory.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/classes/java/rmi/server/RMISocketFactory.java b/jdk/src/share/classes/java/rmi/server/RMISocketFactory.java index e7b7581820b..ec9ade2f54c 100644 --- a/jdk/src/share/classes/java/rmi/server/RMISocketFactory.java +++ b/jdk/src/share/classes/java/rmi/server/RMISocketFactory.java @@ -50,13 +50,13 @@ import java.net.*; * @implNote *

You can use the {@code RMISocketFactory} class to create a server socket that * is bound to a specific address, restricting the origin of requests. For example, - * the following code implements a socket factory that binds server sockets to the + * the following code implements a socket factory that binds server sockets to an IPv4 * loopback address. This restricts RMI to processing requests only from the local host. * *

{@code
  *     class LoopbackSocketFactory extends RMISocketFactory {
  *         public ServerSocket createServerSocket(int port) throws IOException {
- *             return new ServerSocket(port, 5, InetAddress.getLoopbackAddress());
+ *             return new ServerSocket(port, 5, InetAddress.getByName("127.0.0.1"));
  *         }
  *
  *         public Socket createSocket(String host, int port) throws IOException {
@@ -72,8 +72,8 @@ import java.net.*;
  * }
* * Set the {@code java.rmi.server.hostname} system property - * to a host name (typically {@code localhost}) that resolves to the loopback - * interface to ensure that the generated stubs use the right network interface. + * to {@code 127.0.0.1} to ensure that the generated stubs connect to the right + * network interface. * * @author Ann Wollrath * @author Peter Jones From 422a4d5bc7ed2ed9c8324a94c78d95f061d2459e Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 21 Aug 2013 17:15:44 +0200 Subject: [PATCH 18/44] 6417649: -interval=0 is accepted and jconsole doesn't update window content at all Reviewed-by: alanb, jbachorik --- jdk/src/share/classes/sun/tools/jconsole/JConsole.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jdk/src/share/classes/sun/tools/jconsole/JConsole.java b/jdk/src/share/classes/sun/tools/jconsole/JConsole.java index 46d9504dc15..cdb78f94ec9 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/JConsole.java +++ b/jdk/src/share/classes/sun/tools/jconsole/JConsole.java @@ -858,6 +858,10 @@ public class JConsole extends JFrame try { updateInterval = Integer.parseInt(arg.substring(10)) * 1000; + if (updateInterval <= 0) { + usage(); + return; + } } catch (NumberFormatException ex) { usage(); return; From 3cd2e9e0995fe4a2f36ba8fb69f01c51c8155e6f Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 21 Aug 2013 17:17:45 +0200 Subject: [PATCH 19/44] 6359971: Threads tab: Simple text to explain that one can click on a thread to get stack trace Reviewed-by: alanb, jbachorik --- jdk/src/share/classes/sun/tools/jconsole/Messages.java | 1 + jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java | 1 + .../classes/sun/tools/jconsole/resources/messages.properties | 1 + 3 files changed, 3 insertions(+) diff --git a/jdk/src/share/classes/sun/tools/jconsole/Messages.java b/jdk/src/share/classes/sun/tools/jconsole/Messages.java index eee57adcc25..0a3a63e85ca 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/Messages.java +++ b/jdk/src/share/classes/sun/tools/jconsole/Messages.java @@ -271,6 +271,7 @@ final public class Messages { public static String THREADS; public static String THREAD_TAB_THREAD_INFO_ACCESSIBLE_NAME; public static String THREAD_TAB_THREAD_PLOTTER_ACCESSIBLE_NAME; + public static String THREAD_TAB_INITIAL_STACK_TRACE_MESSAGE; public static String THRESHOLD; public static String TILE; public static String TIME_RANGE_COLON; diff --git a/jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java b/jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java index 3932ffa145e..6cf710a2dff 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java +++ b/jdk/src/share/classes/sun/tools/jconsole/ThreadTab.java @@ -596,6 +596,7 @@ class ThreadTab extends Tab implements ActionListener, DocumentListener, ListSel setBorder(thinEmptyBorder); setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + textArea.setText(Messages.THREAD_TAB_INITIAL_STACK_TRACE_MESSAGE); addListSelectionListener(ThreadTab.this); setCellRenderer(new DefaultListCellRenderer() { public Component getListCellRendererComponent(JList list, Object value, int index, diff --git a/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties b/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties index 70ff2f16c6e..832621731b9 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties +++ b/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties @@ -229,6 +229,7 @@ SUMMARY_TAB_VM_VERSION={0} version {1} THREADS=Threads THREAD_TAB_THREAD_INFO_ACCESSIBLE_NAME=Thread Information THREAD_TAB_THREAD_PLOTTER_ACCESSIBLE_NAME=Chart for number of threads. +THREAD_TAB_INITIAL_STACK_TRACE_MESSAGE=[No thread selected] THRESHOLD=Threshold TILE=&Tile TIME_RANGE_COLON=&Time Range: From ff7c51cd184ccf7c61561554eaaab800bf461fb9 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 22 Aug 2013 13:32:22 -0700 Subject: [PATCH 20/44] 6470700: Math.random() / Math.initRNG() uses "double checked locking" Replace class Random variable with a static final holder class Reviewed-by: alanb, mduigou, chegar --- jdk/src/share/classes/java/lang/Math.java | 11 +++-------- jdk/src/share/classes/java/lang/StrictMath.java | 11 +++-------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/jdk/src/share/classes/java/lang/Math.java b/jdk/src/share/classes/java/lang/Math.java index 23bc934688d..ae83e4265ad 100644 --- a/jdk/src/share/classes/java/lang/Math.java +++ b/jdk/src/share/classes/java/lang/Math.java @@ -698,11 +698,8 @@ public final class Math { return 0; } - private static Random randomNumberGenerator; - - private static synchronized Random initRNG() { - Random rnd = randomNumberGenerator; - return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd; + private static final class RandomNumberGeneratorHolder { + static final Random randomNumberGenerator = new Random(); } /** @@ -729,9 +726,7 @@ public final class Math { * @see Random#nextDouble() */ public static double random() { - Random rnd = randomNumberGenerator; - if (rnd == null) rnd = initRNG(); - return rnd.nextDouble(); + return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble(); } /** diff --git a/jdk/src/share/classes/java/lang/StrictMath.java b/jdk/src/share/classes/java/lang/StrictMath.java index eb202d53202..52336484e75 100644 --- a/jdk/src/share/classes/java/lang/StrictMath.java +++ b/jdk/src/share/classes/java/lang/StrictMath.java @@ -678,11 +678,8 @@ public final class StrictMath { return Math.round(a); } - private static Random randomNumberGenerator; - - private static synchronized Random initRNG() { - Random rnd = randomNumberGenerator; - return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd; + private static final class RandomNumberGeneratorHolder { + static final Random randomNumberGenerator = new Random(); } /** @@ -709,9 +706,7 @@ public final class StrictMath { * @see Random#nextDouble() */ public static double random() { - Random rnd = randomNumberGenerator; - if (rnd == null) rnd = initRNG(); - return rnd.nextDouble(); + return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble(); } /** From 6d2de008d77509d89344fddb3dc1dea74888278d Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 23 Aug 2013 20:59:34 +0200 Subject: [PATCH 21/44] 8005899: Logger.getLogger(name, null) should not allow to reset a non-null resource bundle Reviewed-by: mchung, lancea --- .../classes/java/util/logging/Logger.java | 16 +-- .../logging/Logger/getLogger/TestLogger.java | 98 +++++++++++++++++++ .../getLogger/testlogger/MyResource.java | 52 ++++++++++ 3 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 jdk/test/java/util/logging/Logger/getLogger/TestLogger.java create mode 100644 jdk/test/java/util/logging/Logger/getLogger/testlogger/MyResource.java diff --git a/jdk/src/share/classes/java/util/logging/Logger.java b/jdk/src/share/classes/java/util/logging/Logger.java index 1c959ecd6a1..a7f0cc2cd4a 100644 --- a/jdk/src/share/classes/java/util/logging/Logger.java +++ b/jdk/src/share/classes/java/util/logging/Logger.java @@ -457,13 +457,15 @@ public class Logger { * of the subsystem, such as java.net * or javax.swing * @param resourceBundleName name of ResourceBundle to be used for localizing - * messages for this logger. May be null if none of - * the messages require localization. + * messages for this logger. May be {@code null} + * if none of the messages require localization. * @return a suitable Logger * @throws MissingResourceException if the resourceBundleName is non-null and * no corresponding resource can be found. * @throws IllegalArgumentException if the Logger already exists and uses - * a different resource bundle name. + * a different resource bundle name; or if + * {@code resourceBundleName} is {@code null} but the named + * logger has a resource bundle set. * @throws NullPointerException if the name is null. */ @@ -1731,10 +1733,6 @@ public class Logger { // Synchronized to prevent races in setting the fields. private synchronized void setupResourceInfo(String name, Class callersClass) { - if (name == null) { - return; - } - if (resourceBundleName != null) { // this Logger already has a ResourceBundle @@ -1748,6 +1746,10 @@ public class Logger { resourceBundleName + " != " + name); } + if (name == null) { + return; + } + setCallersClassLoaderRef(callersClass); if (findResourceBundle(name, true) == null) { // We've failed to find an expected ResourceBundle. diff --git a/jdk/test/java/util/logging/Logger/getLogger/TestLogger.java b/jdk/test/java/util/logging/Logger/getLogger/TestLogger.java new file mode 100644 index 00000000000..cf6abc449dd --- /dev/null +++ b/jdk/test/java/util/logging/Logger/getLogger/TestLogger.java @@ -0,0 +1,98 @@ +/* + * 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. + */ +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +/** + * @test + * @bug 8005899 + * @build TestLogger testlogger.MyResource + * @run main/othervm TestLogger + * @run main/othervm -Dsecurity=on TestLogger + **/ +public class TestLogger { + + public static final String RESOURCE_BUNDLE = "testlogger.MyResource"; + public static final String ORG_LOGGER = "org"; + public static final String FOO_LOGGER = ORG_LOGGER + ".foo.Foo"; + public static final String BAR_LOGGER = ORG_LOGGER + ".bar.Bar"; + public static final String GEE_LOGGER = ORG_LOGGER + ".gee.Gee"; + public static final String GEE_GEE_LOGGER = GEE_LOGGER+".Gee"; + + public static void main(String[] args) { + final String security = System.getProperty("security", "off"); + System.out.println("Security is " + security); + if ("on".equals(security)) { + System.setSecurityManager(new SecurityManager()); + } + + newLogger(FOO_LOGGER, RESOURCE_BUNDLE); + newLogger(FOO_LOGGER); + newLogger(BAR_LOGGER); + newLogger(BAR_LOGGER, RESOURCE_BUNDLE); + newLogger(GEE_LOGGER, null); + newLogger(GEE_LOGGER, RESOURCE_BUNDLE); + newLogger(ORG_LOGGER); + newLogger(GEE_GEE_LOGGER); + + for (String log : new String[] { FOO_LOGGER, BAR_LOGGER, GEE_LOGGER }) { + if (!RESOURCE_BUNDLE.equals(Logger.getLogger(log).getResourceBundleName())) { + throw new RuntimeException("Shouldn't allow to reset the resource bundle for " + log); + } + try { + Logger logger = Logger.getLogger(log, null); + if (!RESOURCE_BUNDLE.equals(logger.getResourceBundleName())) { + throw new RuntimeException("Shouldn't allow to reset the resource bundle for " + log); + } + throw new RuntimeException("Expected IllegalArgumentException not thrown for " + log); + } catch (IllegalArgumentException e) { + System.out.println("Got expected exception for " + log +": " + e); + } + } + for (String log : new String[] { ORG_LOGGER, GEE_GEE_LOGGER }) { + if (Logger.getLogger(log).getResourceBundleName() != null) { + throw new RuntimeException("Resource bundle is not null for log: " + + Logger.getLogger(log).getResourceBundleName()); + } + try { + Logger logger = Logger.getLogger(log, null); + if (logger.getResourceBundleName() != null) { + throw new RuntimeException("Resource bundle is not null for log: " + + logger.getResourceBundleName()); + } + System.out.println("Success calling Logger.getLogger(\""+log+"\", null)"); + } catch (IllegalArgumentException e) { + throw new RuntimeException("Unexpected exception for " + log +": " + e, e); + } + } + } + + private static List strongRefs = new ArrayList<>(); + private static void newLogger(String name) { + strongRefs.add(Logger.getLogger(name)); + } + private static void newLogger(String name, String resourceBundleName) { + strongRefs.add(Logger.getLogger(name, resourceBundleName)); + } +} diff --git a/jdk/test/java/util/logging/Logger/getLogger/testlogger/MyResource.java b/jdk/test/java/util/logging/Logger/getLogger/testlogger/MyResource.java new file mode 100644 index 00000000000..84b0cd258cb --- /dev/null +++ b/jdk/test/java/util/logging/Logger/getLogger/testlogger/MyResource.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package testlogger; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; +import java.util.ResourceBundle; + +/** + * A dummy resource bundle for testing purposes. + * @author danielfuchs + */ +public class MyResource extends ResourceBundle { + Map bundle = new HashMap<>(); + + @Override + protected Object handleGetObject(String key) { + bundle.put(key,"Localized: " + key); + return bundle.get(key); + } + + @Override + public Enumeration getKeys() { + final Hashtable h = new Hashtable<>(bundle); + return h.keys(); + } + +} From 6c5c2d745abc81a91a7c169edb91538de513881e Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 23 Aug 2013 14:15:54 -0700 Subject: [PATCH 22/44] 6378503: In java.math.BigDecimal, division by one returns zero 6446965: Using BigDecimal.divideToIntegralValue with extreme scales can lead to an incorrect result Fix overflow of ints and ensure appropriate values passed to checkScaleNonZero() Reviewed-by: darcy, martin --- .../share/classes/java/math/BigDecimal.java | 32 +++++++++++-------- .../share/classes/java/math/BigInteger.java | 2 +- .../BigDecimal/IntegralDivisionTests.java | 5 ++- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/jdk/src/share/classes/java/math/BigDecimal.java b/jdk/src/share/classes/java/math/BigDecimal.java index 1a7ca811226..0abfb7522b5 100644 --- a/jdk/src/share/classes/java/math/BigDecimal.java +++ b/jdk/src/share/classes/java/math/BigDecimal.java @@ -2659,28 +2659,32 @@ public class BigDecimal extends Number implements Comparable { if (ys == 0) return 1; - int sdiff = this.scale - val.scale; + long sdiff = (long)this.scale - val.scale; if (sdiff != 0) { // Avoid matching scales if the (adjusted) exponents differ - int xae = this.precision() - this.scale; // [-1] - int yae = val.precision() - val.scale; // [-1] + long xae = (long)this.precision() - this.scale; // [-1] + long yae = (long)val.precision() - val.scale; // [-1] if (xae < yae) return -1; if (xae > yae) return 1; BigInteger rb = null; if (sdiff < 0) { - if ( (xs == INFLATED || - (xs = longMultiplyPowerTen(xs, -sdiff)) == INFLATED) && + // The cases sdiff <= Integer.MIN_VALUE intentionally fall through. + if ( sdiff > Integer.MIN_VALUE && + (xs == INFLATED || + (xs = longMultiplyPowerTen(xs, (int)-sdiff)) == INFLATED) && ys == INFLATED) { - rb = bigMultiplyPowerTen(-sdiff); + rb = bigMultiplyPowerTen((int)-sdiff); return rb.compareMagnitude(val.intVal); } } else { // sdiff > 0 - if ( (ys == INFLATED || - (ys = longMultiplyPowerTen(ys, sdiff)) == INFLATED) && + // The cases sdiff > Integer.MAX_VALUE intentionally fall through. + if ( sdiff <= Integer.MAX_VALUE && + (ys == INFLATED || + (ys = longMultiplyPowerTen(ys, (int)sdiff)) == INFLATED) && xs == INFLATED) { - rb = val.bigMultiplyPowerTen(sdiff); + rb = val.bigMultiplyPowerTen((int)sdiff); return this.intVal.compareMagnitude(rb); } } @@ -4545,7 +4549,7 @@ public class BigDecimal extends Number implements Comparable { if(cmp > 0) { // satisfy constraint (b) yscale -= 1; // [that is, divisor *= 10] int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); - if (checkScaleNonZero((long) mcp + yscale) > xscale) { + if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) { // assert newScale >= xscale int raise = checkScaleNonZero((long) mcp + yscale - xscale); long scaledXs; @@ -4626,7 +4630,7 @@ public class BigDecimal extends Number implements Comparable { // return BigDecimal object whose scale will be set to 'scl'. int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); BigDecimal quotient; - if (checkScaleNonZero((long) mcp + yscale) > xscale) { + if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) { int raise = checkScaleNonZero((long) mcp + yscale - xscale); long scaledXs; if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) { @@ -4673,7 +4677,7 @@ public class BigDecimal extends Number implements Comparable { // return BigDecimal object whose scale will be set to 'scl'. BigDecimal quotient; int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); - if (checkScaleNonZero((long) mcp + yscale) > xscale) { + if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) { int raise = checkScaleNonZero((long) mcp + yscale - xscale); BigInteger rb = bigMultiplyPowerTen(xs,raise); quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); @@ -4714,7 +4718,7 @@ public class BigDecimal extends Number implements Comparable { // return BigDecimal object whose scale will be set to 'scl'. BigDecimal quotient; int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); - if (checkScaleNonZero((long) mcp + yscale) > xscale) { + if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) { int raise = checkScaleNonZero((long) mcp + yscale - xscale); BigInteger rb = bigMultiplyPowerTen(xs,raise); quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); @@ -4745,7 +4749,7 @@ public class BigDecimal extends Number implements Comparable { // return BigDecimal object whose scale will be set to 'scl'. BigDecimal quotient; int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); - if (checkScaleNonZero((long) mcp + yscale) > xscale) { + if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) { int raise = checkScaleNonZero((long) mcp + yscale - xscale); BigInteger rb = bigMultiplyPowerTen(xs,raise); quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); diff --git a/jdk/src/share/classes/java/math/BigInteger.java b/jdk/src/share/classes/java/math/BigInteger.java index e8cedf8a564..6beaed71bb3 100644 --- a/jdk/src/share/classes/java/math/BigInteger.java +++ b/jdk/src/share/classes/java/math/BigInteger.java @@ -2109,7 +2109,7 @@ public class BigInteger extends Number implements Comparable { // This is a quick way to approximate the size of the result, // similar to doing log2[n] * exponent. This will give an upper bound // of how big the result can be, and which algorithm to use. - int scaleFactor = remainingBits * exponent; + long scaleFactor = (long)remainingBits * exponent; // Use slightly different algorithms for small and large operands. // See if the result will safely fit into a long. (Largest 2^63-1) diff --git a/jdk/test/java/math/BigDecimal/IntegralDivisionTests.java b/jdk/test/java/math/BigDecimal/IntegralDivisionTests.java index 1e28e1d7543..ab6b624c98b 100644 --- a/jdk/test/java/math/BigDecimal/IntegralDivisionTests.java +++ b/jdk/test/java/math/BigDecimal/IntegralDivisionTests.java @@ -22,7 +22,7 @@ */ /* * @test - * @bug 4904082 4917089 6337226 + * @bug 4904082 4917089 6337226 6378503 * @summary Tests that integral division and related methods return the proper result and scale. * @author Joseph D. Darcy */ @@ -47,6 +47,9 @@ public class IntegralDivisionTests { {new BigDecimal("400e1"), new BigDecimal("5"), new BigDecimal("80e1")}, {new BigDecimal("400e1"), new BigDecimal("4.999999999"), new BigDecimal("8e2")}, {new BigDecimal("40e2"), new BigDecimal("5"), new BigDecimal("8e2")}, + {BigDecimal.valueOf(1, Integer.MIN_VALUE), + BigDecimal.valueOf(1, -(Integer.MAX_VALUE & 0x7fffff00)), + BigDecimal.valueOf(1, -256)}, }; for(BigDecimal [] testCase: moreTestCases) { From 423284cd203ee03a0d97dc2b63e68567f51b874d Mon Sep 17 00:00:00 2001 From: Yiming Wang Date: Mon, 26 Aug 2013 10:01:27 +0100 Subject: [PATCH 23/44] 8023139: java/nio/file/WatchService/SensitivityModifier.java failing intermittently (win8) Reviewed-by: alanb --- .../WatchService/SensitivityModifier.java | 104 +++++++++--------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/jdk/test/java/nio/file/WatchService/SensitivityModifier.java b/jdk/test/java/nio/file/WatchService/SensitivityModifier.java index 6f9a14cfd60..08722048b63 100644 --- a/jdk/test/java/nio/file/WatchService/SensitivityModifier.java +++ b/jdk/test/java/nio/file/WatchService/SensitivityModifier.java @@ -54,60 +54,66 @@ public class SensitivityModifier { @SuppressWarnings("unchecked") static void doTest(Path top) throws Exception { FileSystem fs = top.getFileSystem(); - WatchService watcher = fs.newWatchService(); + try (WatchService watcher = fs.newWatchService()) { - // create directories and files - int nDirs = 5 + rand.nextInt(20); - int nFiles = 50 + rand.nextInt(50); - Path[] dirs = new Path[nDirs]; - Path[] files = new Path[nFiles]; - for (int i=0; i event = key.pollEvents().iterator().next(); - if (event.kind() != ENTRY_MODIFY) - throw new RuntimeException("Unexpected event: " + event); - Path name = ((WatchEvent)event).context(); - if (!name.equals(file.getFileName())) - throw new RuntimeException("Unexpected context: " + name); - System.out.println("Event OK"); - // drain events (to avoid interference) - do { - key.pollEvents(); - key.reset(); - key = watcher.poll(1, TimeUnit.SECONDS); - } while (key != null); - - // re-register the directories to force changing their sensitivity - // level + // register the directories (random sensitivity) register(dirs, watcher); - } - // done - watcher.close(); + // sleep a bit here to ensure that modification to the first file + // can be detected by polling implementations (ie: last modified time + // may not change otherwise). + try { Thread.sleep(1000); } catch (InterruptedException e) { } + + // modify files and check that events are received + for (int i=0; i<10; i++) { + Path file = files[rand.nextInt(nFiles)]; + System.out.println("Modify: " + file); + try (OutputStream out = Files.newOutputStream(file)) { + out.write(new byte[100]); + } + + System.out.println("Waiting for event(s)..."); + boolean eventReceived = false; + WatchKey key = watcher.take(); + do { + for (WatchEvent event: key.pollEvents()) { + if (event.kind() != ENTRY_MODIFY) + throw new RuntimeException("Unexpected event: " + event); + Path name = ((WatchEvent)event).context(); + if (name.equals(file.getFileName())) { + eventReceived = true; + break; + } + } + key.reset(); + key = watcher.poll(1, TimeUnit.SECONDS); + } while (key != null && !eventReceived); + + // we should have received at least one ENTRY_MODIFY event + if (eventReceived) { + System.out.println("Event OK"); + } else { + throw new RuntimeException("No ENTRY_MODIFY event received for " + file); + } + + // re-register the directories to force changing their sensitivity + // level + register(dirs, watcher); + } + } } public static void main(String[] args) throws Exception { From 910d9b815cd7061261c72570c4d7eeddb0e2d3dc Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Sun, 25 Aug 2013 23:20:59 +0400 Subject: [PATCH 24/44] 7129312: BufferedInputStream calculates negative array size with large streams and mark Reviewed-by: alanb --- .../classes/java/io/BufferedInputStream.java | 19 ++- .../LargeCopyWithMark.java | 117 ++++++++++++++++++ 2 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 jdk/test/java/io/BufferedInputStream/LargeCopyWithMark.java diff --git a/jdk/src/share/classes/java/io/BufferedInputStream.java b/jdk/src/share/classes/java/io/BufferedInputStream.java index a161a988109..fede2feeb7f 100644 --- a/jdk/src/share/classes/java/io/BufferedInputStream.java +++ b/jdk/src/share/classes/java/io/BufferedInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -50,7 +50,15 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; public class BufferedInputStream extends FilterInputStream { - private static int defaultBufferSize = 8192; + private static int DEFAULT_BUFFER_SIZE = 8192; + + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; /** * The internal buffer array where the data is stored. When necessary, @@ -172,7 +180,7 @@ class BufferedInputStream extends FilterInputStream { * @param in the underlying input stream. */ public BufferedInputStream(InputStream in) { - this(in, defaultBufferSize); + this(in, DEFAULT_BUFFER_SIZE); } /** @@ -215,8 +223,11 @@ class BufferedInputStream extends FilterInputStream { } else if (buffer.length >= marklimit) { markpos = -1; /* buffer got too big, invalidate mark */ pos = 0; /* drop buffer contents */ + } else if (buffer.length >= MAX_BUFFER_SIZE) { + throw new OutOfMemoryError("Required array size too large"); } else { /* grow buffer */ - int nsz = pos * 2; + int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? + pos * 2 : MAX_BUFFER_SIZE; if (nsz > marklimit) nsz = marklimit; byte nbuf[] = new byte[nsz]; diff --git a/jdk/test/java/io/BufferedInputStream/LargeCopyWithMark.java b/jdk/test/java/io/BufferedInputStream/LargeCopyWithMark.java new file mode 100644 index 00000000000..2555a1faa5f --- /dev/null +++ b/jdk/test/java/io/BufferedInputStream/LargeCopyWithMark.java @@ -0,0 +1,117 @@ +/* + * 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 7129312 + * @summary BufferedInputStream calculates negative array size with large + * streams and mark + * @library /lib/testlibrary + * @run main/othervm LargeCopyWithMark + */ + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import static jdk.testlibrary.ProcessTools.*; + + +public class LargeCopyWithMark { + + public static void main(String[] args) throws Exception { + if (! System.getProperty("os.arch").contains("64")) { + System.out.println("Test runs on 64 bit platforms"); + return; + } + ProcessBuilder pb = createJavaProcessBuilder("-Xmx4G", + "-ea:LargeCopyWithMark$Child", + "LargeCopyWithMark$Child"); + int res = pb.inheritIO().start().waitFor(); + if (res != 0) { + throw new AssertionError("Test failed: exit code = " + res); + } + } + + public static class Child { + static final int BUFF_SIZE = 8192; + static final int BIS_BUFF_SIZE = Integer.MAX_VALUE / 2 + 100; + static final long BYTES_TO_COPY = 2L * Integer.MAX_VALUE; + + static { + assert BIS_BUFF_SIZE * 2 < 0 : "doubling must overflow"; + } + + public static void main(String[] args) throws Exception { + byte[] buff = new byte[BUFF_SIZE]; + + try (InputStream myis = new MyInputStream(BYTES_TO_COPY); + InputStream bis = new BufferedInputStream(myis, BIS_BUFF_SIZE); + OutputStream myos = new MyOutputStream()) { + + // will require a buffer bigger than BIS_BUFF_SIZE + bis.mark(BIS_BUFF_SIZE + 100); + + for (;;) { + int count = bis.read(buff, 0, BUFF_SIZE); + if (count == -1) + break; + myos.write(buff, 0, count); + } + } catch (java.lang.NegativeArraySizeException e) { + e.printStackTrace(); + System.exit(11); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} + +class MyInputStream extends InputStream { + private long bytesLeft; + public MyInputStream(long bytesLeft) { + this.bytesLeft = bytesLeft; + } + @Override public int read() throws IOException { + return 0; + } + @Override public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + @Override public int read(byte[] b, int off, int len) throws IOException { + if (bytesLeft <= 0) + return -1; + long result = Math.min(bytesLeft, (long)len); + bytesLeft -= result; + return (int)result; + } + @Override public int available() throws IOException { + return (bytesLeft > 0) ? 1 : 0; + } +} + +class MyOutputStream extends OutputStream { + @Override public void write(int b) throws IOException {} + @Override public void write(byte[] b) throws IOException {} + @Override public void write(byte[] b, int off, int len) throws IOException {} +} From d4b28471ff7518d2800568b0739249ab4037e22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Borggr=C3=A9n-Franck?= Date: Mon, 26 Aug 2013 13:38:14 +0200 Subject: [PATCH 25/44] 8022343: j.l.Class.getAnnotatedSuperclass() doesn't return null in some cases Reviewed-by: darcy, vromero, psandoz --- jdk/src/share/classes/java/lang/Class.java | 12 +++- .../annotation/TypeAnnotationReflection.java | 4 +- .../GetAnnotatedSuperclass.java | 56 +++++++++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java diff --git a/jdk/src/share/classes/java/lang/Class.java b/jdk/src/share/classes/java/lang/Class.java index 9df0805167b..a3c962e0838 100644 --- a/jdk/src/share/classes/java/lang/Class.java +++ b/jdk/src/share/classes/java/lang/Class.java @@ -3338,8 +3338,16 @@ public final class Class implements java.io.Serializable, * @since 1.8 */ public AnnotatedType getAnnotatedSuperclass() { - return TypeAnnotationParser.buildAnnotatedSuperclass(getRawTypeAnnotations(), getConstantPool(), this); -} + if (this == Object.class || + isInterface() || + isArray() || + isPrimitive() || + this == Void.TYPE) { + return null; + } + + return TypeAnnotationParser.buildAnnotatedSuperclass(getRawTypeAnnotations(), getConstantPool(), this); + } /** * Returns an array of AnnotatedType objects that represent the use of types to diff --git a/jdk/test/java/lang/annotation/TypeAnnotationReflection.java b/jdk/test/java/lang/annotation/TypeAnnotationReflection.java index 6b4d167ef80..2c7da746a7f 100644 --- a/jdk/test/java/lang/annotation/TypeAnnotationReflection.java +++ b/jdk/test/java/lang/annotation/TypeAnnotationReflection.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8004698 8007073 + * @bug 8004698 8007073 8022343 * @summary Unit test for type annotations */ @@ -58,7 +58,7 @@ public class TypeAnnotationReflection { } private static void testSuper() throws Exception { - check(Object.class.getAnnotatedSuperclass().getAnnotations().length == 0); + check(Object.class.getAnnotatedSuperclass() == null); check(Class.class.getAnnotatedSuperclass().getAnnotations().length == 0); AnnotatedType a; diff --git a/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java b/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java new file mode 100644 index 00000000000..d112203a90f --- /dev/null +++ b/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java @@ -0,0 +1,56 @@ +/* + * 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 8022343 + * @summary make sure Class.getAnnotatedSuperclass() returns null when specified to do so + */ + +public class GetAnnotatedSuperclass { + private static final Class[] testData = { + Object.class, + If.class, + Object[].class, + void.class, + int.class, + }; + + public static void main(String[] args) throws Exception { + int failed = 0; + for (Class toTest : testData) { + Object res = toTest.getAnnotatedSuperclass(); + + if (res != null) { + failed++; + System.out.println(toTest + ".getAnnotatedSuperclass() returns: " + + res + ", should be null"); + } + } + + if (failed != 0) + throw new RuntimeException("Test failed, check log for details"); + } + + interface If {} +} From 56dbd896c3173d6e0df7af1e92565e590b005869 Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Mon, 26 Aug 2013 17:50:34 +0400 Subject: [PATCH 26/44] 8023234: StampedLock serializes readers on writer unlock Sync-up the fix from jsr166 CVS, signal more readers on writer unlock Reviewed-by: martin, shade --- .../util/concurrent/locks/StampedLock.java | 364 ++++++++++-------- .../ReadersUnlockAfterWriteUnlock.java | 88 +++++ 2 files changed, 286 insertions(+), 166 deletions(-) create mode 100644 jdk/test/java/util/concurrent/locks/StampedLock/ReadersUnlockAfterWriteUnlock.java diff --git a/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java b/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java index 1506e5a4e46..5fe20b6a578 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java @@ -226,7 +226,11 @@ public class StampedLock implements java.io.Serializable { * incoming reader arrives while read lock is held but there is a * queued writer, this incoming reader is queued. (This rule is * responsible for some of the complexity of method acquireRead, - * but without it, the lock becomes highly unfair.) + * but without it, the lock becomes highly unfair.) Method release + * does not (and sometimes cannot) itself wake up cowaiters. This + * is done by the primary thread, but helped by any other threads + * with nothing better to do in methods acquireRead and + * acquireWrite. * * These rules apply to threads actually queued. All tryLock forms * opportunistically try to acquire locks regardless of preference @@ -267,11 +271,14 @@ public class StampedLock implements java.io.Serializable { /** Number of processors, for spin control */ private static final int NCPU = Runtime.getRuntime().availableProcessors(); - /** Maximum number of retries before blocking on acquisition */ + /** Maximum number of retries before enqueuing on acquisition */ private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0; + /** Maximum number of retries before blocking at head on acquisition */ + private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0; + /** Maximum number of retries before re-blocking */ - private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 12 : 0; + private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0; /** The period for yielding when waiting for overflow spinlock */ private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1 @@ -415,8 +422,8 @@ public class StampedLock implements java.io.Serializable { * @return a stamp that can be used to unlock or convert mode */ public long readLock() { - long s, next; // bypass acquireRead on fully unlocked case only - return ((((s = state) & ABITS) == 0L && + long s = state, next; // bypass acquireRead on common uncontended case + return ((whead == wtail && (s & ABITS) < RFULL && U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ? next : acquireRead(false, 0L)); } @@ -1012,17 +1019,8 @@ public class StampedLock implements java.io.Serializable { if (t.status <= 0) q = t; } - if (q != null) { - for (WNode r = q;;) { // release co-waiters too - if ((w = r.thread) != null) { - r.thread = null; - U.unpark(w); - } - if ((r = q.cowait) == null) - break; - U.compareAndSwapObject(q, WCOWAIT, r, r.cowait); - } - } + if (q != null && (w = q.thread) != null) + U.unpark(w); } } @@ -1038,22 +1036,22 @@ public class StampedLock implements java.io.Serializable { private long acquireWrite(boolean interruptible, long deadline) { WNode node = null, p; for (int spins = -1;;) { // spin while enqueuing - long s, ns; - if (((s = state) & ABITS) == 0L) { + long m, s, ns; + if ((m = (s = state) & ABITS) == 0L) { if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) return ns; } + else if (spins < 0) + spins = (m == WBIT && wtail == whead) ? SPINS : 0; else if (spins > 0) { if (LockSupport.nextSecondarySeed() >= 0) --spins; } else if ((p = wtail) == null) { // initialize queue - WNode h = new WNode(WMODE, null); - if (U.compareAndSwapObject(this, WHEAD, null, h)) - wtail = h; + WNode hd = new WNode(WMODE, null); + if (U.compareAndSwapObject(this, WHEAD, null, hd)) + wtail = hd; } - else if (spins < 0) - spins = (p == whead) ? SPINS : 0; else if (node == null) node = new WNode(WMODE, p); else if (node.prev != p) @@ -1064,14 +1062,18 @@ public class StampedLock implements java.io.Serializable { } } - for (int spins = SPINS;;) { - WNode np, pp; int ps; long s, ns; Thread w; - while ((np = node.prev) != p && np != null) - (p = np).next = node; // stale - if (whead == p) { + for (int spins = -1;;) { + WNode h, np, pp; int ps; + if ((h = whead) == p) { + if (spins < 0) + spins = HEAD_SPINS; + else if (spins < MAX_HEAD_SPINS) + spins <<= 1; for (int k = spins;;) { // spin at head + long s, ns; if (((s = state) & ABITS) == 0L) { - if (U.compareAndSwapLong(this, STATE, s, ns = s+WBIT)) { + if (U.compareAndSwapLong(this, STATE, s, + ns = s + WBIT)) { whead = node; node.prev = null; return ns; @@ -1081,33 +1083,45 @@ public class StampedLock implements java.io.Serializable { --k <= 0) break; } - if (spins < MAX_HEAD_SPINS) - spins <<= 1; } - if ((ps = p.status) == 0) - U.compareAndSwapInt(p, WSTATUS, 0, WAITING); - else if (ps == CANCELLED) { - if ((pp = p.prev) != null) { - node.prev = pp; - pp.next = node; + else if (h != null) { // help release stale waiters + WNode c; Thread w; + while ((c = h.cowait) != null) { + if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && + (w = c.thread) != null) + U.unpark(w); } } - else { - long time; // 0 argument to park means no timeout - if (deadline == 0L) - time = 0L; - else if ((time = deadline - System.nanoTime()) <= 0L) - return cancelWaiter(node, node, false); - Thread wt = Thread.currentThread(); - U.putObject(wt, PARKBLOCKER, this); // emulate LockSupport.park - node.thread = wt; - if (node.prev == p && p.status == WAITING && // recheck - (p != whead || (state & ABITS) != 0L)) - U.park(false, time); - node.thread = null; - U.putObject(wt, PARKBLOCKER, null); - if (interruptible && Thread.interrupted()) - return cancelWaiter(node, node, true); + if (whead == h) { + if ((np = node.prev) != p) { + if (np != null) + (p = np).next = node; // stale + } + else if ((ps = p.status) == 0) + U.compareAndSwapInt(p, WSTATUS, 0, WAITING); + else if (ps == CANCELLED) { + if ((pp = p.prev) != null) { + node.prev = pp; + pp.next = node; + } + } + else { + long time; // 0 argument to park means no timeout + if (deadline == 0L) + time = 0L; + else if ((time = deadline - System.nanoTime()) <= 0L) + return cancelWaiter(node, node, false); + Thread wt = Thread.currentThread(); + U.putObject(wt, PARKBLOCKER, this); + node.thread = wt; + if (p.status < 0 && (p != h || (state & ABITS) != 0L) && + whead == h && node.prev == p) + U.park(false, time); // emulate LockSupport.park + node.thread = null; + U.putObject(wt, PARKBLOCKER, null); + if (interruptible && Thread.interrupted()) + return cancelWaiter(node, node, true); + } } } } @@ -1122,138 +1136,159 @@ public class StampedLock implements java.io.Serializable { * @return next state, or INTERRUPTED */ private long acquireRead(boolean interruptible, long deadline) { - WNode node = null, group = null, p; + WNode node = null, p; for (int spins = -1;;) { - for (;;) { - long s, m, ns; WNode h, q; Thread w; // anti-barging guard - if (group == null && (h = whead) != null && - (q = h.next) != null && q.mode != RMODE) - break; - if ((m = (s = state) & ABITS) < RFULL ? - U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : - (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { - if (group != null) { // help release others - for (WNode r = group;;) { - if ((w = r.thread) != null) { - r.thread = null; - U.unpark(w); + WNode h; + if ((h = whead) == (p = wtail)) { + for (long m, s, ns;;) { + if ((m = (s = state) & ABITS) < RFULL ? + U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : + (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) + return ns; + else if (m >= WBIT) { + if (spins > 0) { + if (LockSupport.nextSecondarySeed() >= 0) + --spins; + } + else { + if (spins == 0) { + WNode nh = whead, np = wtail; + if ((nh == h && np == p) || (h = nh) != (p = np)) + break; } - if ((r = group.cowait) == null) - break; - U.compareAndSwapObject(group, WCOWAIT, r, r.cowait); + spins = SPINS; } } - return ns; } - if (m >= WBIT) - break; } - if (spins > 0) { - if (LockSupport.nextSecondarySeed() >= 0) - --spins; + if (p == null) { // initialize queue + WNode hd = new WNode(WMODE, null); + if (U.compareAndSwapObject(this, WHEAD, null, hd)) + wtail = hd; } - else if ((p = wtail) == null) { - WNode h = new WNode(WMODE, null); - if (U.compareAndSwapObject(this, WHEAD, null, h)) - wtail = h; - } - else if (spins < 0) - spins = (p == whead) ? SPINS : 0; else if (node == null) - node = new WNode(WMODE, p); - else if (node.prev != p) - node.prev = p; - else if (p.mode == RMODE && p != whead) { - WNode pp = p.prev; // become co-waiter with group p - if (pp != null && p == wtail && - U.compareAndSwapObject(p, WCOWAIT, - node.cowait = p.cowait, node)) { - node.thread = Thread.currentThread(); - for (long time;;) { + node = new WNode(RMODE, p); + else if (h == p || p.mode != RMODE) { + if (node.prev != p) + node.prev = p; + else if (U.compareAndSwapObject(this, WTAIL, p, node)) { + p.next = node; + break; + } + } + else if (!U.compareAndSwapObject(p, WCOWAIT, + node.cowait = p.cowait, node)) + node.cowait = null; + else { + for (;;) { + WNode pp, c; Thread w; + if ((h = whead) != null && (c = h.cowait) != null && + U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && + (w = c.thread) != null) // help release + U.unpark(w); + if (h == (pp = p.prev) || h == p || pp == null) { + long m, s, ns; + do { + if ((m = (s = state) & ABITS) < RFULL ? + U.compareAndSwapLong(this, STATE, s, + ns = s + RUNIT) : + (m < WBIT && + (ns = tryIncReaderOverflow(s)) != 0L)) + return ns; + } while (m < WBIT); + } + if (whead == h && p.prev == pp) { + long time; + if (pp == null || h == p || p.status > 0) { + node = null; // throw away + break; + } if (deadline == 0L) time = 0L; else if ((time = deadline - System.nanoTime()) <= 0L) return cancelWaiter(node, p, false); - if (node.thread == null) - break; - if (p.prev != pp || p.status == CANCELLED || - p == whead || p.prev != pp) { - node.thread = null; - break; - } Thread wt = Thread.currentThread(); U.putObject(wt, PARKBLOCKER, this); - if (node.thread == null) // must recheck - break; - U.park(false, time); + node.thread = wt; + if ((h != pp || (state & ABITS) == WBIT) && + whead == h && p.prev == pp) + U.park(false, time); + node.thread = null; U.putObject(wt, PARKBLOCKER, null); if (interruptible && Thread.interrupted()) return cancelWaiter(node, p, true); } - group = p; } - node = null; // throw away - } - else if (U.compareAndSwapObject(this, WTAIL, p, node)) { - p.next = node; - break; } } - for (int spins = SPINS;;) { - WNode np, pp, r; int ps; long m, s, ns; Thread w; - while ((np = node.prev) != p && np != null) - (p = np).next = node; - if (whead == p) { - for (int k = spins;;) { - if ((m = (s = state) & ABITS) != WBIT) { - if (m < RFULL ? - U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT): - (ns = tryIncReaderOverflow(s)) != 0L) { - whead = node; - node.prev = null; - while ((r = node.cowait) != null) { - if (U.compareAndSwapObject(node, WCOWAIT, - r, r.cowait) && - (w = r.thread) != null) { - r.thread = null; - U.unpark(w); // release co-waiter - } - } - return ns; + for (int spins = -1;;) { + WNode h, np, pp; int ps; + if ((h = whead) == p) { + if (spins < 0) + spins = HEAD_SPINS; + else if (spins < MAX_HEAD_SPINS) + spins <<= 1; + for (int k = spins;;) { // spin at head + long m, s, ns; + if ((m = (s = state) & ABITS) < RFULL ? + U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : + (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { + WNode c; Thread w; + whead = node; + node.prev = null; + while ((c = node.cowait) != null) { + if (U.compareAndSwapObject(node, WCOWAIT, + c, c.cowait) && + (w = c.thread) != null) + U.unpark(w); } + return ns; } - else if (LockSupport.nextSecondarySeed() >= 0 && - --k <= 0) + else if (m >= WBIT && + LockSupport.nextSecondarySeed() >= 0 && --k <= 0) break; } - if (spins < MAX_HEAD_SPINS) - spins <<= 1; } - if ((ps = p.status) == 0) - U.compareAndSwapInt(p, WSTATUS, 0, WAITING); - else if (ps == CANCELLED) { - if ((pp = p.prev) != null) { - node.prev = pp; - pp.next = node; + else if (h != null) { + WNode c; Thread w; + while ((c = h.cowait) != null) { + if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && + (w = c.thread) != null) + U.unpark(w); } } - else { - long time; - if (deadline == 0L) - time = 0L; - else if ((time = deadline - System.nanoTime()) <= 0L) - return cancelWaiter(node, node, false); - Thread wt = Thread.currentThread(); - U.putObject(wt, PARKBLOCKER, this); - node.thread = wt; - if (node.prev == p && p.status == WAITING && - (p != whead || (state & ABITS) != WBIT)) - U.park(false, time); - node.thread = null; - U.putObject(wt, PARKBLOCKER, null); - if (interruptible && Thread.interrupted()) - return cancelWaiter(node, node, true); + if (whead == h) { + if ((np = node.prev) != p) { + if (np != null) + (p = np).next = node; // stale + } + else if ((ps = p.status) == 0) + U.compareAndSwapInt(p, WSTATUS, 0, WAITING); + else if (ps == CANCELLED) { + if ((pp = p.prev) != null) { + node.prev = pp; + pp.next = node; + } + } + else { + long time; + if (deadline == 0L) + time = 0L; + else if ((time = deadline - System.nanoTime()) <= 0L) + return cancelWaiter(node, node, false); + Thread wt = Thread.currentThread(); + U.putObject(wt, PARKBLOCKER, this); + node.thread = wt; + if (p.status < 0 && + (p != h || (state & ABITS) == WBIT) && + whead == h && node.prev == p) + U.park(false, time); + node.thread = null; + U.putObject(wt, PARKBLOCKER, null); + if (interruptible && Thread.interrupted()) + return cancelWaiter(node, node, true); + } } } } @@ -1278,22 +1313,19 @@ public class StampedLock implements java.io.Serializable { if (node != null && group != null) { Thread w; node.status = CANCELLED; - node.thread = null; // unsplice cancelled nodes from group for (WNode p = group, q; (q = p.cowait) != null;) { - if (q.status == CANCELLED) - U.compareAndSwapObject(p, WNEXT, q, q.next); + if (q.status == CANCELLED) { + U.compareAndSwapObject(p, WCOWAIT, q, q.cowait); + p = group; // restart + } else p = q; } if (group == node) { - WNode r; // detach and wake up uncancelled co-waiters - while ((r = node.cowait) != null) { - if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) && - (w = r.thread) != null) { - r.thread = null; - U.unpark(w); - } + for (WNode r = group.cowait; r != null; r = r.cowait) { + if ((w = r.thread) != null) + U.unpark(w); // wake up uncancelled co-waiters } for (WNode pred = node.prev; pred != null; ) { // unsplice WNode succ, pp; // find valid successor diff --git a/jdk/test/java/util/concurrent/locks/StampedLock/ReadersUnlockAfterWriteUnlock.java b/jdk/test/java/util/concurrent/locks/StampedLock/ReadersUnlockAfterWriteUnlock.java new file mode 100644 index 00000000000..6d459372515 --- /dev/null +++ b/jdk/test/java/util/concurrent/locks/StampedLock/ReadersUnlockAfterWriteUnlock.java @@ -0,0 +1,88 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 + * @run main/othervm/timeout=60 ReadersUnlockAfterWriteUnlock + * @bug 8023234 + * @summary StampedLock serializes readers on writer unlock + * @author Dmitry Chyuko + * @author Aleksey Shipilev + */ + +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.locks.StampedLock; + +public class ReadersUnlockAfterWriteUnlock { + static final int RNUM = 2; + static final StampedLock sl = new StampedLock(); + static volatile boolean isDone; + + static CyclicBarrier iterationStart = new CyclicBarrier(RNUM + 1); + static CyclicBarrier readersHaveLocks = new CyclicBarrier(RNUM); + static CyclicBarrier writerHasLock = new CyclicBarrier(RNUM + 1); + + static class Reader extends Thread { + final String name; + Reader(String name) { + super(); + this.name = name; + } + public void run() { + while (!isDone && !isInterrupted()) { + try { + iterationStart.await(); + writerHasLock.await(); + long rs = sl.readLock(); + + // single reader blocks here indefinitely if readers + // are serialized + readersHaveLocks.await(); + + sl.unlockRead(rs); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + } + } + + public static void main(String[] args) throws InterruptedException { + for (int r = 0 ; r < RNUM; ++r) { + new Reader("r" + r).start(); + } + int i; + for (i = 0; i < 1024; ++i) { + try { + iterationStart.await(); + long ws = sl.writeLock(); + writerHasLock.await(); + Thread.sleep(10); + sl.unlockWrite(ws); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + isDone = true; + } + +} From e0b682f2d8b912abc0f94c00cecf1709f746bfc7 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Mon, 26 Aug 2013 11:46:05 -0400 Subject: [PATCH 27/44] 8011944: Sort fails with ArrayIndexOutOfBoundsException Increase the size of pending stack and add test cases Reviewed-by: alanb --- .../classes/java/util/ComparableTimSort.java | 3 +- jdk/src/share/classes/java/util/TimSort.java | 3 +- .../java/util/Arrays/TimSortStackSize.java | 116 ++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/util/Arrays/TimSortStackSize.java diff --git a/jdk/src/share/classes/java/util/ComparableTimSort.java b/jdk/src/share/classes/java/util/ComparableTimSort.java index 76b5fd56a00..e7c7ac020bd 100644 --- a/jdk/src/share/classes/java/util/ComparableTimSort.java +++ b/jdk/src/share/classes/java/util/ComparableTimSort.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright 2009 Google Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -146,7 +147,7 @@ class ComparableTimSort { */ int stackLen = (len < 120 ? 5 : len < 1542 ? 10 : - len < 119151 ? 19 : 40); + len < 119151 ? 24 : 40); runBase = new int[stackLen]; runLen = new int[stackLen]; } diff --git a/jdk/src/share/classes/java/util/TimSort.java b/jdk/src/share/classes/java/util/TimSort.java index 35493ff0bd6..9966f74df37 100644 --- a/jdk/src/share/classes/java/util/TimSort.java +++ b/jdk/src/share/classes/java/util/TimSort.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright 2009 Google Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -176,7 +177,7 @@ class TimSort { */ int stackLen = (len < 120 ? 5 : len < 1542 ? 10 : - len < 119151 ? 19 : 40); + len < 119151 ? 24 : 40); runBase = new int[stackLen]; runLen = new int[stackLen]; } diff --git a/jdk/test/java/util/Arrays/TimSortStackSize.java b/jdk/test/java/util/Arrays/TimSortStackSize.java new file mode 100644 index 00000000000..c05cc52a163 --- /dev/null +++ b/jdk/test/java/util/Arrays/TimSortStackSize.java @@ -0,0 +1,116 @@ +/* + * 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 8011944 + * @summary Test TimSort stack size + */ +import java.util.Arrays; +import java.util.ArrayDeque; + +public class TimSortStackSize { + + public static void main(String[] args) { + testComparableTimSort(); + testTimSort(); + } + + static void testComparableTimSort() { + System.out.printf("testComparableTimSort()%n"); + Arrays.sort(genData()); + } + + static void testTimSort() { + System.out.printf("testTimSort()%n"); + Arrays.sort(genData(), Integer::compare); + } + + private static final int MIN = 16; + + private static final int BOUND1 = 2 * MIN + 1; + private static final int BOUND2 = BOUND1 + MIN + 2; + private static final int BOUND3 = BOUND1 + 1 + BOUND2; + private static final int BOUND4 = BOUND2 + 1 + BOUND3; + private static final int BOUND5 = BOUND3 + 1 + BOUND4; + + static int build(int size, int B, ArrayDeque chunks) { + chunks.addFirst(B); + if (size < BOUND1) { + chunks.addFirst(size); + return size; + } + + int asize = (size + 2) / 2; + if (size >= BOUND2 && asize < BOUND1) { + asize = BOUND1; + } else if (size >= BOUND3 && asize < BOUND2) { + asize = BOUND2; + } else if (size >= BOUND4 && asize < BOUND3) { + asize = BOUND3; + } else if (size >= BOUND5 && asize < BOUND4) { + asize = BOUND4; + } + if (size - asize >= B) { + throw new AssertionError(" " + size + " , " + asize + " , " + B); + } + return build(asize, size - asize, chunks); + } + + static Integer[] genData() { + ArrayDeque chunks = new ArrayDeque(); + chunks.addFirst(MIN); + + int B = MIN + 4; + int A = B + MIN + 1; + + for (int i = 0; i < 8; i++) { + int eps = build(A, B, chunks); + B = B + A + 1; + A = B + eps + 1; + } + chunks.addFirst(B); + chunks.addFirst(A); + int total = 0; + for (Integer len : chunks) { + total += len; + } + int pow = MIN; + while (pow < total) { + pow += pow; + } + chunks.addLast(pow - total); + System.out.println(" Total: " + total); + Integer[] array = new Integer[pow]; + int off = 0; + int pos = 0; + for (Integer len : chunks) { + for (int i = 0; i < len; i++) { + array[pos++] = Integer.valueOf(i == 0 ? 0 : 1); + } + off++; + } + return array; + } + +} From 86af118ec0e78d3228fbd5647981005034a61ceb Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Mon, 26 Aug 2013 18:26:35 +0400 Subject: [PATCH 28/44] 8016018: Typo in AbstractStringBuilder#indexOf and #lastIndexOf descriptions Reviewed-by: alanb, chegar --- jdk/src/share/classes/java/lang/AbstractStringBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java index a5bde616f8a..3260da6ae99 100644 --- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java +++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java @@ -1307,7 +1307,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * specified substring, starting at the specified index. The integer * returned is the smallest value {@code k} for which: *
-     *     k >= Math.min(fromIndex, str.length()) &&
+     *     k >= Math.min(fromIndex, this.length()) &&
      *                   this.toString().startsWith(str, k)
      * 
* If no such value of k exists, then -1 is returned. @@ -1346,7 +1346,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * specified substring. The integer returned is the largest value k * such that: *
-     *     k <= Math.min(fromIndex, str.length()) &&
+     *     k <= Math.min(fromIndex, this.length()) &&
      *                   this.toString().startsWith(str, k)
      * 
* If no such value of k exists, then -1 is returned. From 5c937b723c0325ed52203efa9e707780b60dc57a Mon Sep 17 00:00:00 2001 From: Bill Pittore Date: Mon, 26 Aug 2013 11:27:48 -0400 Subject: [PATCH 29/44] 8014135: The JVMTI specification does not conform to recent changes in JNI specification Added support for statically linked agents Reviewed-by: alanb, sspitsyn, bobv, coleenp --- .../com/sun/tools/attach/VirtualMachine.java | 81 ++++++++++++------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/jdk/src/share/classes/com/sun/tools/attach/VirtualMachine.java b/jdk/src/share/classes/com/sun/tools/attach/VirtualMachine.java index aad0be2cfc9..29464d88da6 100644 --- a/jdk/src/share/classes/com/sun/tools/attach/VirtualMachine.java +++ b/jdk/src/share/classes/com/sun/tools/attach/VirtualMachine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -59,7 +59,7 @@ import java.io.IOException; * {@link java.lang.instrument} for a detailed description on how these agents * are loaded and started). The {@link #loadAgentLibrary loadAgentLibrary} and * {@link #loadAgentPath loadAgentPath} methods are used to load agents that - * are deployed in a dynamic library and make use of the JVM Tools * Interface.

* @@ -298,25 +298,29 @@ public abstract class VirtualMachine { *

A JVM * TI client is called an agent. It is developed in a native language. * A JVM TI agent is deployed in a platform specific manner but it is typically the - * platform equivalent of a dynamic library. This method causes the given agent - * library to be loaded into the target VM (if not already loaded). + * platform equivalent of a dynamic library. Alternatively, it may be statically linked into the VM. + * This method causes the given agent library to be loaded into the target + * VM (if not already loaded or if not statically linked into the VM). * It then causes the target VM to invoke the Agent_OnAttach function + * or, for a statically linked agent named 'L', the Agent_OnAttach_L function * as specified in the * JVM Tools - * Interface specification. Note that the Agent_OnAttach + * Interface specification. Note that the Agent_OnAttach[_L] * function is invoked even if the agent library was loaded prior to invoking * this method. * *

The agent library provided is the name of the agent library. It is interpreted * in the target virtual machine in an implementation-dependent manner. Typically an * implementation will expand the library name into an operating system specific file - * name. For example, on UNIX systems, the name foo might be expanded to - * libfoo.so, and located using the search path specified by the - * LD_LIBRARY_PATH environment variable.

+ * name. For example, on UNIX systems, the name L might be expanded to + * libL.so, and located using the search path specified by the + * LD_LIBRARY_PATH environment variable. If the agent named 'L' is + * statically linked into the VM then the VM must export a function named + * Agent_OnAttach_L.

* - *

If the Agent_OnAttach function in the agent library returns + *

If the Agent_OnAttach[_L] function in the agent library returns * an error then an {@link com.sun.tools.attach.AgentInitializationException} is - * thrown. The return value from the Agent_OnAttach can then be + * thrown. The return value from the Agent_OnAttach[_L] can then be * obtained by invoking the {@link * com.sun.tools.attach.AgentInitializationException#returnValue() returnValue} * method on the exception.

@@ -325,15 +329,16 @@ public abstract class VirtualMachine { * The name of the agent library. * * @param options - * The options to provide to the Agent_OnAttach + * The options to provide to the Agent_OnAttach[_L] * function (can be null). * * @throws AgentLoadException - * If the agent library does not exist, or cannot be loaded for - * another reason. + * If the agent library does not exist, the agent library is not + * statically linked with the VM, or the agent library cannot be + * loaded for another reason. * * @throws AgentInitializationException - * If the Agent_OnAttach function returns an error + * If the Agent_OnAttach[_L] function returns an error. * * @throws IOException * If an I/O error occurs @@ -359,11 +364,12 @@ public abstract class VirtualMachine { * The name of the agent library. * * @throws AgentLoadException - * If the agent library does not exist, or cannot be loaded for - * another reason. + * If the agent library does not exist, the agent library is not + * statically linked with the VM, or the agent library cannot be + * loaded for another reason. * * @throws AgentInitializationException - * If the Agent_OnAttach function returns an error + * If the Agent_OnAttach[_L] function returns an error. * * @throws IOException * If an I/O error occurs @@ -383,12 +389,23 @@ public abstract class VirtualMachine { *

A JVM * TI client is called an agent. It is developed in a native language. * A JVM TI agent is deployed in a platform specific manner but it is typically the - * platform equivalent of a dynamic library. This method causes the given agent - * library to be loaded into the target VM (if not already loaded). - * It then causes the target VM to invoke the Agent_OnAttach function - * as specified in the + * platform equivalent of a dynamic library. Alternatively, the native + * library specified by the agentPath parameter may be statically + * linked with the VM. The parsing of the agentPath parameter into + * a statically linked library name is done in a platform + * specific manner in the VM. For example, in UNIX, an agentPath parameter + * of /a/b/libL.so would name a library 'L'. + * + * See the JVM TI Specification for more details. + * + * This method causes the given agent library to be loaded into the target + * VM (if not already loaded or if not statically linked into the VM). + * It then causes the target VM to invoke the Agent_OnAttach + * function or, for a statically linked agent named 'L', the + * Agent_OnAttach_L function as specified in the * JVM Tools - * Interface specification. Note that the Agent_OnAttach + * Interface specification. + * Note that the Agent_OnAttach[_L] * function is invoked even if the agent library was loaded prior to invoking * this method. * @@ -396,9 +413,9 @@ public abstract class VirtualMachine { * agent library. Unlike {@link #loadAgentLibrary loadAgentLibrary}, the library name * is not expanded in the target virtual machine.

* - *

If the Agent_OnAttach function in the agent library returns + *

If the Agent_OnAttach[_L] function in the agent library returns * an error then an {@link com.sun.tools.attach.AgentInitializationException} is - * thrown. The return value from the Agent_OnAttach can then be + * thrown. The return value from the Agent_OnAttach[_L] can then be * obtained by invoking the {@link * com.sun.tools.attach.AgentInitializationException#returnValue() returnValue} * method on the exception.

@@ -407,15 +424,16 @@ public abstract class VirtualMachine { * The full path of the agent library. * * @param options - * The options to provide to the Agent_OnAttach + * The options to provide to the Agent_OnAttach[_L] * function (can be null). * * @throws AgentLoadException - * If the agent library does not exist, or cannot be loaded for - * another reason. + * If the agent library does not exist, the agent library is not + * statically linked with the VM, or the agent library cannot be + * loaded for another reason. * * @throws AgentInitializationException - * If the Agent_OnAttach function returns an error + * If the Agent_OnAttach[_L] function returns an error. * * @throws IOException * If an I/O error occurs @@ -441,11 +459,12 @@ public abstract class VirtualMachine { * The full path to the agent library. * * @throws AgentLoadException - * If the agent library does not exist, or cannot be loaded for - * another reason. + * If the agent library does not exist, the agent library is not + * statically linked with the VM, or the agent library cannot be + * loaded for another reason. * * @throws AgentInitializationException - * If the Agent_OnAttach function returns an error + * If the Agent_OnAttach[_L] function returns an error. * * @throws IOException * If an I/O error occurs From 231a351a47d4d3fb8034115584bef6847486bc68 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Mon, 26 Aug 2013 22:55:03 +0200 Subject: [PATCH 30/44] 8020292: j.u.SplittableRandom Co-authored-by: Guy Steele Co-authored-by: Doug Lea Co-authored-by: Brian Goetz Reviewed-by: mduigou --- .../classes/java/util/SplittableRandom.java | 1002 +++++++++++++++++ .../SplittableRandomTest.java | 511 +++++++++ .../tests/java/util/SplittableRandomTest.java | 367 ++++++ 3 files changed, 1880 insertions(+) create mode 100644 jdk/src/share/classes/java/util/SplittableRandom.java create mode 100644 jdk/test/java/util/SplittableRandom/SplittableRandomTest.java create mode 100644 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/SplittableRandomTest.java diff --git a/jdk/src/share/classes/java/util/SplittableRandom.java b/jdk/src/share/classes/java/util/SplittableRandom.java new file mode 100644 index 00000000000..5a990f4d215 --- /dev/null +++ b/jdk/src/share/classes/java/util/SplittableRandom.java @@ -0,0 +1,1002 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.security.SecureRandom; +import java.net.InetAddress; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; +import java.util.function.DoubleConsumer; +import java.util.stream.StreamSupport; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.DoubleStream; + +/** + * A generator of uniform pseudorandom values applicable for use in + * (among other contexts) isolated parallel computations that may + * generate subtasks. Class {@code SplittableRandom} supports methods for + * producing pseudorandom numbers of type {@code int}, {@code long}, + * and {@code double} with similar usages as for class + * {@link java.util.Random} but differs in the following ways: + * + *
    + * + *
  • Series of generated values pass the DieHarder suite testing + * independence and uniformity properties of random number generators. + * (Most recently validated with version + * 3.31.1.) These tests validate only the methods for certain + * types and ranges, but similar properties are expected to hold, at + * least approximately, for others as well. The period + * (length of any series of generated values before it repeats) is at + * least 264.
  • + * + *
  • Method {@link #split} constructs and returns a new + * SplittableRandom instance that shares no mutable state with the + * current instance. However, with very high probability, the + * values collectively generated by the two objects have the same + * statistical properties as if the same quantity of values were + * generated by a single thread using a single {@code + * SplittableRandom} object.
  • + * + *
  • Instances of SplittableRandom are not thread-safe. + * They are designed to be split, not shared, across threads. For + * example, a {@link java.util.concurrent.ForkJoinTask + * fork/join-style} computation using random numbers might include a + * construction of the form {@code new + * Subtask(aSplittableRandom.split()).fork()}. + * + *
  • This class provides additional methods for generating random + * streams, that employ the above techniques when used in {@code + * stream.parallel()} mode.
  • + * + *
+ * + *

Instances of {@code SplittableRandom} are not cryptographically + * secure. Consider instead using {@link java.security.SecureRandom} + * in security-sensitive applications. Additionally, + * default-constructed instances do not use a cryptographically random + * seed unless the {@linkplain System#getProperty system property} + * {@code java.util.secureRandomSeed} is set to {@code true}. + * + * @author Guy Steele + * @author Doug Lea + * @since 1.8 + */ +public final class SplittableRandom { + + /* + * Implementation Overview. + * + * This algorithm was inspired by the "DotMix" algorithm by + * Leiserson, Schardl, and Sukha "Deterministic Parallel + * Random-Number Generation for Dynamic-Multithreading Platforms", + * PPoPP 2012, as well as those in "Parallel random numbers: as + * easy as 1, 2, 3" by Salmon, Morae, Dror, and Shaw, SC 2011. It + * differs mainly in simplifying and cheapening operations. + * + * The primary update step (method nextSeed()) is to add a + * constant ("gamma") to the current (64 bit) seed, forming a + * simple sequence. The seed and the gamma values for any two + * SplittableRandom instances are highly likely to be different. + * + * Methods nextLong, nextInt, and derivatives do not return the + * sequence (seed) values, but instead a hash-like bit-mix of + * their bits, producing more independently distributed sequences. + * For nextLong, the mix64 bit-mixing function computes the same + * value as the "64-bit finalizer" function in Austin Appleby's + * MurmurHash3 algorithm. See + * http://code.google.com/p/smhasher/wiki/MurmurHash3 , which + * comments: "The constants for the finalizers were generated by a + * simple simulated-annealing algorithm, and both avalanche all + * bits of 'h' to within 0.25% bias." The mix32 function is + * equivalent to (int)(mix64(seed) >>> 32), but faster because it + * omits a step that doesn't contribute to result. + * + * The split operation uses the current generator to form the seed + * and gamma for another SplittableRandom. To conservatively + * avoid potential correlations between seed and value generation, + * gamma selection (method nextGamma) uses the "Mix13" constants + * for MurmurHash3 described by David Stafford + * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html) + * To avoid potential weaknesses in bit-mixing transformations, we + * restrict gammas to odd values with at least 12 and no more than + * 52 bits set. Rather than rejecting candidates with too few or + * too many bits set, method nextGamma flips some bits (which has + * the effect of mapping at most 4 to any given gamma value). + * This reduces the effective set of 64bit odd gamma values by + * about 214, a very tiny percentage, and serves as an + * automated screening for sequence constant selection that is + * left as an empirical decision in some other hashing and crypto + * algorithms. + * + * The resulting generator thus transforms a sequence in which + * (typically) many bits change on each step, with an inexpensive + * mixer with good (but less than cryptographically secure) + * avalanching. + * + * The default (no-argument) constructor, in essence, invokes + * split() for a common "seeder" SplittableRandom. Unlike other + * cases, this split must be performed in a thread-safe manner, so + * we use an AtomicLong to represent the seed rather than use an + * explicit SplittableRandom. To bootstrap the seeder, we start + * off using a seed based on current time and host unless the + * java.util.secureRandomSeed property is set. This serves as a + * slimmed-down (and insecure) variant of SecureRandom that also + * avoids stalls that may occur when using /dev/random. + * + * It is a relatively simple matter to apply the basic design here + * to use 128 bit seeds. However, emulating 128bit arithmetic and + * carrying around twice the state add more overhead than appears + * warranted for current usages. + * + * File organization: First the non-public methods that constitute + * the main algorithm, then the main public methods, followed by + * some custom spliterator classes needed for stream methods. + */ + + /** + * The initial gamma value for (unsplit) SplittableRandoms. Must + * be odd with at least 12 and no more than 52 bits set. Currently + * set to the golden ratio scaled to 64bits. + */ + private static final long INITIAL_GAMMA = 0x9e3779b97f4a7c15L; + + /** + * The least non-zero value returned by nextDouble(). This value + * is scaled by a random value of 53 bits to produce a result. + */ + private static final double DOUBLE_UNIT = 1.0 / (1L << 53); + + /** + * The seed. Updated only via method nextSeed. + */ + private long seed; + + /** + * The step value. + */ + private final long gamma; + + /** + * Internal constructor used by all others except default constructor. + */ + private SplittableRandom(long seed, long gamma) { + this.seed = seed; + this.gamma = gamma; + } + + /** + * Computes MurmurHash3 64bit mix function. + */ + private static long mix64(long z) { + z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; + z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L; + return z ^ (z >>> 33); + } + + /** + * Returns the 32 high bits of mix64(z) as int. + */ + private static int mix32(long z) { + z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; + return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32); + } + + /** + * Returns the gamma value to use for a new split instance. + */ + private static long nextGamma(long z) { + z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L; // Stafford "Mix13" + z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL; + z = (z ^ (z >>> 31)) | 1L; // force to be odd + int n = Long.bitCount(z); // ensure enough 0 and 1 bits + return (n < 12 || n > 52) ? z ^ 0xaaaaaaaaaaaaaaaaL : z; + } + + /** + * Adds gamma to seed. + */ + private long nextSeed() { + return seed += gamma; + } + + /** + * The seed generator for default constructors. + */ + private static final AtomicLong seeder = new AtomicLong(initialSeed()); + + private static long initialSeed() { + String pp = java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction( + "java.util.secureRandomSeed")); + if (pp != null && pp.equalsIgnoreCase("true")) { + byte[] seedBytes = java.security.SecureRandom.getSeed(8); + long s = (long)(seedBytes[0]) & 0xffL; + for (int i = 1; i < 8; ++i) + s = (s << 8) | ((long)(seedBytes[i]) & 0xffL); + return s; + } + int hh = 0; // hashed host address + try { + hh = InetAddress.getLocalHost().hashCode(); + } catch (Exception ignore) { + } + return (mix64((((long)hh) << 32) ^ System.currentTimeMillis()) ^ + mix64(System.nanoTime())); + } + + // IllegalArgumentException messages + static final String BadBound = "bound must be positive"; + static final String BadRange = "bound must be greater than origin"; + static final String BadSize = "size must be non-negative"; + + /* + * Internal versions of nextX methods used by streams, as well as + * the public nextX(origin, bound) methods. These exist mainly to + * avoid the need for multiple versions of stream spliterators + * across the different exported forms of streams. + */ + + /** + * The form of nextLong used by LongStream Spliterators. If + * origin is greater than bound, acts as unbounded form of + * nextLong, else as bounded form. + * + * @param origin the least value, unless greater than bound + * @param bound the upper bound (exclusive), must not equal origin + * @return a pseudorandom value + */ + final long internalNextLong(long origin, long bound) { + /* + * Four Cases: + * + * 1. If the arguments indicate unbounded form, act as + * nextLong(). + * + * 2. If the range is an exact power of two, apply the + * associated bit mask. + * + * 3. If the range is positive, loop to avoid potential bias + * when the implicit nextLong() bound (264) is not + * evenly divisible by the range. The loop rejects candidates + * computed from otherwise over-represented values. The + * expected number of iterations under an ideal generator + * varies from 1 to 2, depending on the bound. The loop itself + * takes an unlovable form. Because the first candidate is + * already available, we need a break-in-the-middle + * construction, which is concisely but cryptically performed + * within the while-condition of a body-less for loop. + * + * 4. Otherwise, the range cannot be represented as a positive + * long. The loop repeatedly generates unbounded longs until + * obtaining a candidate meeting constraints (with an expected + * number of iterations of less than two). + */ + + long r = mix64(nextSeed()); + if (origin < bound) { + long n = bound - origin, m = n - 1; + if ((n & m) == 0L) // power of two + r = (r & m) + origin; + else if (n > 0L) { // reject over-represented candidates + for (long u = r >>> 1; // ensure nonnegative + u + m - (r = u % n) < 0L; // rejection check + u = mix64(nextSeed()) >>> 1) // retry + ; + r += origin; + } + else { // range not representable as long + while (r < origin || r >= bound) + r = mix64(nextSeed()); + } + } + return r; + } + + /** + * The form of nextInt used by IntStream Spliterators. + * Exactly the same as long version, except for types. + * + * @param origin the least value, unless greater than bound + * @param bound the upper bound (exclusive), must not equal origin + * @return a pseudorandom value + */ + final int internalNextInt(int origin, int bound) { + int r = mix32(nextSeed()); + if (origin < bound) { + int n = bound - origin, m = n - 1; + if ((n & m) == 0) + r = (r & m) + origin; + else if (n > 0) { + for (int u = r >>> 1; + u + m - (r = u % n) < 0; + u = mix32(nextSeed()) >>> 1) + ; + r += origin; + } + else { + while (r < origin || r >= bound) + r = mix32(nextSeed()); + } + } + return r; + } + + /** + * The form of nextDouble used by DoubleStream Spliterators. + * + * @param origin the least value, unless greater than bound + * @param bound the upper bound (exclusive), must not equal origin + * @return a pseudorandom value + */ + final double internalNextDouble(double origin, double bound) { + double r = (nextLong() >>> 11) * DOUBLE_UNIT; + if (origin < bound) { + r = r * (bound - origin) + origin; + if (r >= bound) // correct for rounding + r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1); + } + return r; + } + + /* ---------------- public methods ---------------- */ + + /** + * Creates a new SplittableRandom instance using the specified + * initial seed. SplittableRandom instances created with the same + * seed in the same program generate identical sequences of values. + * + * @param seed the initial seed + */ + public SplittableRandom(long seed) { + this(seed, INITIAL_GAMMA); + } + + /** + * Creates a new SplittableRandom instance that is likely to + * generate sequences of values that are statistically independent + * of those of any other instances in the current program; and + * may, and typically does, vary across program invocations. + */ + public SplittableRandom() { // emulate seeder.split() + this.gamma = nextGamma(this.seed = seeder.addAndGet(INITIAL_GAMMA)); + } + + /** + * Constructs and returns a new SplittableRandom instance that + * shares no mutable state with this instance. However, with very + * high probability, the set of values collectively generated by + * the two objects has the same statistical properties as if the + * same quantity of values were generated by a single thread using + * a single SplittableRandom object. Either or both of the two + * objects may be further split using the {@code split()} method, + * and the same expected statistical properties apply to the + * entire set of generators constructed by such recursive + * splitting. + * + * @return the new SplittableRandom instance + */ + public SplittableRandom split() { + long s = nextSeed(); + return new SplittableRandom(s, nextGamma(s)); + } + + /** + * Returns a pseudorandom {@code int} value. + * + * @return a pseudorandom {@code int} value + */ + public int nextInt() { + return mix32(nextSeed()); + } + + /** + * Returns a pseudorandom {@code int} value between zero (inclusive) + * and the specified bound (exclusive). + * + * @param bound the upper bound (exclusive). Must be positive. + * @return a pseudorandom {@code int} value between zero + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code bound} is not positive + */ + public int nextInt(int bound) { + if (bound <= 0) + throw new IllegalArgumentException(BadBound); + // Specialize internalNextInt for origin 0 + int r = mix32(nextSeed()); + int m = bound - 1; + if ((bound & m) == 0) // power of two + r &= m; + else { // reject over-represented candidates + for (int u = r >>> 1; + u + m - (r = u % bound) < 0; + u = mix32(nextSeed()) >>> 1) + ; + } + return r; + } + + /** + * Returns a pseudorandom {@code int} value between the specified + * origin (inclusive) and the specified bound (exclusive). + * + * @param origin the least value returned + * @param bound the upper bound (exclusive) + * @return a pseudorandom {@code int} value between the origin + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code origin} is greater than + * or equal to {@code bound} + */ + public int nextInt(int origin, int bound) { + if (origin >= bound) + throw new IllegalArgumentException(BadRange); + return internalNextInt(origin, bound); + } + + /** + * Returns a pseudorandom {@code long} value. + * + * @return a pseudorandom {@code long} value + */ + public long nextLong() { + return mix64(nextSeed()); + } + + /** + * Returns a pseudorandom {@code long} value between zero (inclusive) + * and the specified bound (exclusive). + * + * @param bound the upper bound (exclusive). Must be positive. + * @return a pseudorandom {@code long} value between zero + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code bound} is not positive + */ + public long nextLong(long bound) { + if (bound <= 0) + throw new IllegalArgumentException(BadBound); + // Specialize internalNextLong for origin 0 + long r = mix64(nextSeed()); + long m = bound - 1; + if ((bound & m) == 0L) // power of two + r &= m; + else { // reject over-represented candidates + for (long u = r >>> 1; + u + m - (r = u % bound) < 0L; + u = mix64(nextSeed()) >>> 1) + ; + } + return r; + } + + /** + * Returns a pseudorandom {@code long} value between the specified + * origin (inclusive) and the specified bound (exclusive). + * + * @param origin the least value returned + * @param bound the upper bound (exclusive) + * @return a pseudorandom {@code long} value between the origin + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code origin} is greater than + * or equal to {@code bound} + */ + public long nextLong(long origin, long bound) { + if (origin >= bound) + throw new IllegalArgumentException(BadRange); + return internalNextLong(origin, bound); + } + + /** + * Returns a pseudorandom {@code double} value between zero + * (inclusive) and one (exclusive). + * + * @return a pseudorandom {@code double} value between zero + * (inclusive) and one (exclusive) + */ + public double nextDouble() { + return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT; + } + + /** + * Returns a pseudorandom {@code double} value between 0.0 + * (inclusive) and the specified bound (exclusive). + * + * @param bound the upper bound (exclusive). Must be positive. + * @return a pseudorandom {@code double} value between zero + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code bound} is not positive + */ + public double nextDouble(double bound) { + if (!(bound > 0.0)) + throw new IllegalArgumentException(BadBound); + double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound; + return (result < bound) ? result : // correct for rounding + Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1); + } + + /** + * Returns a pseudorandom {@code double} value between the specified + * origin (inclusive) and bound (exclusive). + * + * @param origin the least value returned + * @param bound the upper bound (exclusive) + * @return a pseudorandom {@code double} value between the origin + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code origin} is greater than + * or equal to {@code bound} + */ + public double nextDouble(double origin, double bound) { + if (!(origin < bound)) + throw new IllegalArgumentException(BadRange); + return internalNextDouble(origin, bound); + } + + /** + * Returns a pseudorandom {@code boolean} value. + * + * @return a pseudorandom {@code boolean} value + */ + public boolean nextBoolean() { + return mix32(nextSeed()) < 0; + } + + // stream methods, coded in a way intended to better isolate for + // maintenance purposes the small differences across forms. + + /** + * Returns a stream producing the given {@code streamSize} number + * of pseudorandom {@code int} values from this generator and/or + * one split from it. + * + * @param streamSize the number of values to generate + * @return a stream of pseudorandom {@code int} values + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + */ + public IntStream ints(long streamSize) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + return StreamSupport.intStream + (new RandomIntsSpliterator + (this, 0L, streamSize, Integer.MAX_VALUE, 0), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code int} + * values from this generator and/or one split from it. + * + * @implNote This method is implemented to be equivalent to {@code + * ints(Long.MAX_VALUE)}. + * + * @return a stream of pseudorandom {@code int} values + */ + public IntStream ints() { + return StreamSupport.intStream + (new RandomIntsSpliterator + (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number + * of pseudorandom {@code int} values from this generator and/or one split + * from it; each value conforms to the given origin (inclusive) and bound + * (exclusive). + * + * @param streamSize the number of values to generate + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code int} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero, or {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + */ + public IntStream ints(long streamSize, int randomNumberOrigin, + int randomNumberBound) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.intStream + (new RandomIntsSpliterator + (this, 0L, streamSize, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * int} values from this generator and/or one split from it; each value + * conforms to the given origin (inclusive) and bound (exclusive). + * + * @implNote This method is implemented to be equivalent to {@code + * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}. + * + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code int} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + */ + public IntStream ints(int randomNumberOrigin, int randomNumberBound) { + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.intStream + (new RandomIntsSpliterator + (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number + * of pseudorandom {@code long} values from this generator and/or + * one split from it. + * + * @param streamSize the number of values to generate + * @return a stream of pseudorandom {@code long} values + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + */ + public LongStream longs(long streamSize) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + return StreamSupport.longStream + (new RandomLongsSpliterator + (this, 0L, streamSize, Long.MAX_VALUE, 0L), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * long} values from this generator and/or one split from it. + * + * @implNote This method is implemented to be equivalent to {@code + * longs(Long.MAX_VALUE)}. + * + * @return a stream of pseudorandom {@code long} values + */ + public LongStream longs() { + return StreamSupport.longStream + (new RandomLongsSpliterator + (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code long} values from this generator and/or one split + * from it; each value conforms to the given origin (inclusive) and bound + * (exclusive). + * + * @param streamSize the number of values to generate + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code long} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero, or {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + */ + public LongStream longs(long streamSize, long randomNumberOrigin, + long randomNumberBound) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.longStream + (new RandomLongsSpliterator + (this, 0L, streamSize, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * long} values from this generator and/or one split from it; each value + * conforms to the given origin (inclusive) and bound (exclusive). + * + * @implNote This method is implemented to be equivalent to {@code + * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}. + * + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code long} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + */ + public LongStream longs(long randomNumberOrigin, long randomNumberBound) { + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.longStream + (new RandomLongsSpliterator + (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code double} values from this generator and/or one split + * from it; each value is between zero (inclusive) and one (exclusive). + * + * @param streamSize the number of values to generate + * @return a stream of {@code double} values + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + */ + public DoubleStream doubles(long streamSize) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (this, 0L, streamSize, Double.MAX_VALUE, 0.0), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * double} values from this generator and/or one split from it; each value + * is between zero (inclusive) and one (exclusive). + * + * @implNote This method is implemented to be equivalent to {@code + * doubles(Long.MAX_VALUE)}. + * + * @return a stream of pseudorandom {@code double} values + */ + public DoubleStream doubles() { + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code double} values from this generator and/or one split + * from it; each value conforms to the given origin (inclusive) and bound + * (exclusive). + * + * @param streamSize the number of values to generate + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code double} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + */ + public DoubleStream doubles(long streamSize, double randomNumberOrigin, + double randomNumberBound) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + if (!(randomNumberOrigin < randomNumberBound)) + throw new IllegalArgumentException(BadRange); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (this, 0L, streamSize, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * double} values from this generator and/or one split from it; each value + * conforms to the given origin (inclusive) and bound (exclusive). + * + * @implNote This method is implemented to be equivalent to {@code + * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}. + * + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code double} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + */ + public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) { + if (!(randomNumberOrigin < randomNumberBound)) + throw new IllegalArgumentException(BadRange); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Spliterator for int streams. We multiplex the four int + * versions into one class by treating a bound less than origin as + * unbounded, and also by treating "infinite" as equivalent to + * Long.MAX_VALUE. For splits, it uses the standard divide-by-two + * approach. The long and double versions of this class are + * identical except for types. + */ + static final class RandomIntsSpliterator implements Spliterator.OfInt { + final SplittableRandom rng; + long index; + final long fence; + final int origin; + final int bound; + RandomIntsSpliterator(SplittableRandom rng, long index, long fence, + int origin, int bound) { + this.rng = rng; this.index = index; this.fence = fence; + this.origin = origin; this.bound = bound; + } + + public RandomIntsSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomIntsSpliterator(rng.split(), i, index = m, origin, bound); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + public boolean tryAdvance(IntConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(rng.internalNextInt(origin, bound)); + index = i + 1; + return true; + } + return false; + } + + public void forEachRemaining(IntConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + index = f; + SplittableRandom r = rng; + int o = origin, b = bound; + do { + consumer.accept(r.internalNextInt(o, b)); + } while (++i < f); + } + } + } + + /** + * Spliterator for long streams. + */ + static final class RandomLongsSpliterator implements Spliterator.OfLong { + final SplittableRandom rng; + long index; + final long fence; + final long origin; + final long bound; + RandomLongsSpliterator(SplittableRandom rng, long index, long fence, + long origin, long bound) { + this.rng = rng; this.index = index; this.fence = fence; + this.origin = origin; this.bound = bound; + } + + public RandomLongsSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomLongsSpliterator(rng.split(), i, index = m, origin, bound); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + public boolean tryAdvance(LongConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(rng.internalNextLong(origin, bound)); + index = i + 1; + return true; + } + return false; + } + + public void forEachRemaining(LongConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + index = f; + SplittableRandom r = rng; + long o = origin, b = bound; + do { + consumer.accept(r.internalNextLong(o, b)); + } while (++i < f); + } + } + + } + + /** + * Spliterator for double streams. + */ + static final class RandomDoublesSpliterator implements Spliterator.OfDouble { + final SplittableRandom rng; + long index; + final long fence; + final double origin; + final double bound; + RandomDoublesSpliterator(SplittableRandom rng, long index, long fence, + double origin, double bound) { + this.rng = rng; this.index = index; this.fence = fence; + this.origin = origin; this.bound = bound; + } + + public RandomDoublesSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomDoublesSpliterator(rng.split(), i, index = m, origin, bound); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + public boolean tryAdvance(DoubleConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(rng.internalNextDouble(origin, bound)); + index = i + 1; + return true; + } + return false; + } + + public void forEachRemaining(DoubleConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + index = f; + SplittableRandom r = rng; + double o = origin, b = bound; + do { + consumer.accept(r.internalNextDouble(o, b)); + } while (++i < f); + } + } + } + +} diff --git a/jdk/test/java/util/SplittableRandom/SplittableRandomTest.java b/jdk/test/java/util/SplittableRandom/SplittableRandomTest.java new file mode 100644 index 00000000000..23ed242d06d --- /dev/null +++ b/jdk/test/java/util/SplittableRandom/SplittableRandomTest.java @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2012, 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. + */ + +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.SplittableRandom; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAdder; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +/** + * @test + * @run testng SplittableRandomTest + * @run testng/othervm -Djava.util.secureRandomSeed=true SplittableRandomTest + * @summary test methods on SplittableRandom + */ +@Test +public class SplittableRandomTest { + + // Note: this test was copied from the 166 TCK SplittableRandomTest test + // and modified to be a TestNG test + + /* + * Testing coverage notes: + * + * 1. Many of the test methods are adapted from ThreadLocalRandomTest. + * + * 2. These tests do not check for random number generator quality. + * But we check for minimal API compliance by requiring that + * repeated calls to nextX methods, up to NCALLS tries, produce at + * least two distinct results. (In some possible universe, a + * "correct" implementation might fail, but the odds are vastly + * less than that of encountering a hardware failure while running + * the test.) For bounded nextX methods, we sample various + * intervals across multiples of primes. In other tests, we repeat + * under REPS different values. + */ + + // max numbers of calls to detect getting stuck on one value + static final int NCALLS = 10000; + + // max sampled int bound + static final int MAX_INT_BOUND = (1 << 28); + + // max sampled long bound + static final long MAX_LONG_BOUND = (1L << 42); + + // Number of replications for other checks + static final int REPS = 20; + + /** + * Repeated calls to nextInt produce at least two distinct results + */ + public void testNextInt() { + SplittableRandom sr = new SplittableRandom(); + int f = sr.nextInt(); + int i = 0; + while (i < NCALLS && sr.nextInt() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextLong produce at least two distinct results + */ + public void testNextLong() { + SplittableRandom sr = new SplittableRandom(); + long f = sr.nextLong(); + int i = 0; + while (i < NCALLS && sr.nextLong() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextDouble produce at least two distinct results + */ + public void testNextDouble() { + SplittableRandom sr = new SplittableRandom(); + double f = sr.nextDouble(); + int i = 0; + while (i < NCALLS && sr.nextDouble() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Two SplittableRandoms created with the same seed produce the + * same values for nextLong. + */ + public void testSeedConstructor() { + for (long seed = 2; seed < MAX_LONG_BOUND; seed += 15485863) { + SplittableRandom sr1 = new SplittableRandom(seed); + SplittableRandom sr2 = new SplittableRandom(seed); + for (int i = 0; i < REPS; ++i) + assertEquals(sr1.nextLong(), sr2.nextLong()); + } + } + + /** + * A SplittableRandom produced by split() of a default-constructed + * SplittableRandom generates a different sequence + */ + public void testSplit1() { + SplittableRandom sr = new SplittableRandom(); + for (int reps = 0; reps < REPS; ++reps) { + SplittableRandom sc = sr.split(); + int i = 0; + while (i < NCALLS && sr.nextLong() == sc.nextLong()) + ++i; + assertTrue(i < NCALLS); + } + } + + /** + * A SplittableRandom produced by split() of a seeded-constructed + * SplittableRandom generates a different sequence + */ + public void testSplit2() { + SplittableRandom sr = new SplittableRandom(12345); + for (int reps = 0; reps < REPS; ++reps) { + SplittableRandom sc = sr.split(); + int i = 0; + while (i < NCALLS && sr.nextLong() == sc.nextLong()) + ++i; + assertTrue(i < NCALLS); + } + } + + /** + * nextInt(negative) throws IllegalArgumentException + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNextIntBoundedNeg() { + SplittableRandom sr = new SplittableRandom(); + int f = sr.nextInt(-17); + } + + /** + * nextInt(least >= bound) throws IllegalArgumentException + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNextIntBadBounds() { + SplittableRandom sr = new SplittableRandom(); + int f = sr.nextInt(17, 2); + } + + /** + * nextInt(bound) returns 0 <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextIntBounded() { + SplittableRandom sr = new SplittableRandom(); + // sample bound space across prime number increments + for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) { + int f = sr.nextInt(bound); + assertTrue(0 <= f && f < bound); + int i = 0; + int j; + while (i < NCALLS && + (j = sr.nextInt(bound)) == f) { + assertTrue(0 <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + + /** + * nextInt(least, bound) returns least <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextIntBounded2() { + SplittableRandom sr = new SplittableRandom(); + for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) { + for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) { + int f = sr.nextInt(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + int j; + while (i < NCALLS && + (j = sr.nextInt(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * nextLong(negative) throws IllegalArgumentException + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNextLongBoundedNeg() { + SplittableRandom sr = new SplittableRandom(); + long f = sr.nextLong(-17); + } + + /** + * nextLong(least >= bound) throws IllegalArgumentException + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNextLongBadBounds() { + SplittableRandom sr = new SplittableRandom(); + long f = sr.nextLong(17, 2); + } + + /** + * nextLong(bound) returns 0 <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextLongBounded() { + SplittableRandom sr = new SplittableRandom(); + for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) { + long f = sr.nextLong(bound); + assertTrue(0 <= f && f < bound); + int i = 0; + long j; + while (i < NCALLS && + (j = sr.nextLong(bound)) == f) { + assertTrue(0 <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + + /** + * nextLong(least, bound) returns least <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextLongBounded2() { + SplittableRandom sr = new SplittableRandom(); + for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) { + for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { + long f = sr.nextLong(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + long j; + while (i < NCALLS && + (j = sr.nextLong(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * nextDouble(least, bound) returns least <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextDoubleBounded2() { + SplittableRandom sr = new SplittableRandom(); + for (double least = 0.0001; least < 1.0e20; least *= 8) { + for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) { + double f = sr.nextDouble(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + double j; + while (i < NCALLS && + (j = sr.nextDouble(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * Invoking sized ints, long, doubles, with negative sizes throws + * IllegalArgumentException + */ + public void testBadStreamSize() { + SplittableRandom r = new SplittableRandom(); + executeAndCatchIAE(() -> r.ints(-1L)); + executeAndCatchIAE(() -> r.ints(-1L, 2, 3)); + executeAndCatchIAE(() -> r.longs(-1L)); + executeAndCatchIAE(() -> r.longs(-1L, -1L, 1L)); + executeAndCatchIAE(() -> r.doubles(-1L)); + executeAndCatchIAE(() -> r.doubles(-1L, .5, .6)); + } + + /** + * Invoking bounded ints, long, doubles, with illegal bounds throws + * IllegalArgumentException + */ + public void testBadStreamBounds() { + SplittableRandom r = new SplittableRandom(); + executeAndCatchIAE(() -> r.ints(2, 1)); + executeAndCatchIAE(() -> r.ints(10, 42, 42)); + executeAndCatchIAE(() -> r.longs(-1L, -1L)); + executeAndCatchIAE(() -> r.longs(10, 1L, -2L)); + executeAndCatchIAE(() -> r.doubles(0.0, 0.0)); + executeAndCatchIAE(() -> r.doubles(10, .5, .4)); + } + + private void executeAndCatchIAE(Runnable r) { + executeAndCatch(IllegalArgumentException.class, r); + } + + private void executeAndCatch(Class expected, Runnable r) { + Exception caught = null; + try { + r.run(); + } + catch (Exception e) { + caught = e; + } + + assertNotNull(caught, + String.format("No Exception was thrown, expected an Exception of %s to be thrown", + expected.getName())); + Assert.assertTrue(expected.isInstance(caught), + String.format("Exception thrown %s not an instance of %s", + caught.getClass().getName(), expected.getName())); + } + + /** + * A parallel sized stream of ints generates the given number of values + */ + public void testIntsCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.ints(size).parallel().forEach(x -> {counter.increment();}); + assertEquals(counter.sum(), size); + size += 524959; + } + } + + /** + * A parallel sized stream of longs generates the given number of values + */ + public void testLongsCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.longs(size).parallel().forEach(x -> {counter.increment();}); + assertEquals(counter.sum(), size); + size += 524959; + } + } + + /** + * A parallel sized stream of doubles generates the given number of values + */ + public void testDoublesCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.doubles(size).parallel().forEach(x -> {counter.increment();}); + assertEquals(counter.sum(), size); + size += 524959; + } + } + + /** + * Each of a parallel sized stream of bounded ints is within bounds + */ + public void testBoundedInts() { + AtomicInteger fails = new AtomicInteger(0); + SplittableRandom r = new SplittableRandom(); + long size = 12345L; + for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) { + for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) { + final int lo = least, hi = bound; + r.ints(size, lo, hi).parallel(). + forEach(x -> {if (x < lo || x >= hi) + fails.getAndIncrement(); }); + } + } + assertEquals(fails.get(), 0); + } + + /** + * Each of a parallel sized stream of bounded longs is within bounds + */ + public void testBoundedLongs() { + AtomicInteger fails = new AtomicInteger(0); + SplittableRandom r = new SplittableRandom(); + long size = 123L; + for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) { + for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { + final long lo = least, hi = bound; + r.longs(size, lo, hi).parallel(). + forEach(x -> {if (x < lo || x >= hi) + fails.getAndIncrement(); }); + } + } + assertEquals(fails.get(), 0); + } + + /** + * Each of a parallel sized stream of bounded doubles is within bounds + */ + public void testBoundedDoubles() { + AtomicInteger fails = new AtomicInteger(0); + SplittableRandom r = new SplittableRandom(); + long size = 456; + for (double least = 0.00011; least < 1.0e20; least *= 9) { + for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) { + final double lo = least, hi = bound; + r.doubles(size, lo, hi).parallel(). + forEach(x -> {if (x < lo || x >= hi) + fails.getAndIncrement(); }); + } + } + assertEquals(fails.get(), 0); + } + + /** + * A parallel unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.ints().limit(size).parallel().forEach(x -> {counter.increment();}); + assertEquals(counter.sum(), size); + } + + /** + * A parallel unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.longs().limit(size).parallel().forEach(x -> {counter.increment();}); + assertEquals(counter.sum(), size); + } + + /** + * A parallel unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.doubles().limit(size).parallel().forEach(x -> {counter.increment();}); + assertEquals(counter.sum(), size); + } + + /** + * A sequential unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCountSeq() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.ints().limit(size).forEach(x -> {counter.increment();}); + assertEquals(counter.sum(), size); + } + + /** + * A sequential unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCountSeq() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.longs().limit(size).forEach(x -> {counter.increment();}); + assertEquals(counter.sum(), size); + } + + /** + * A sequential unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCountSeq() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.doubles().limit(size).forEach(x -> {counter.increment();}); + assertEquals(counter.sum(), size); + } + +} diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/SplittableRandomTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/SplittableRandomTest.java new file mode 100644 index 00000000000..30b5e7d6da8 --- /dev/null +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/SplittableRandomTest.java @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.tests.java.util; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Spliterator; +import java.util.SplittableRandom; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.DoubleStream; +import java.util.stream.DoubleStreamTestScenario; +import java.util.stream.IntStream; +import java.util.stream.IntStreamTestScenario; +import java.util.stream.LongStream; +import java.util.stream.LongStreamTestScenario; +import java.util.stream.OpTestCase; +import java.util.stream.StreamSupport; +import java.util.stream.TestData; + +@Test +public class SplittableRandomTest extends OpTestCase { + + static class RandomBoxedSpliterator implements Spliterator { + final SplittableRandom rng; + long index; + final long fence; + final Function rngF; + + RandomBoxedSpliterator(SplittableRandom rng, long index, long fence, Function rngF) { + this.rng = rng; + this.index = index; + this.fence = fence; + this.rngF = rngF; + } + + public RandomBoxedSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomBoxedSpliterator<>(rng.split(), i, index = m, rngF); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + @Override + public boolean tryAdvance(Consumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(rngF.apply(rng)); + index = i + 1; + return true; + } + return false; + } + } + + static final int SIZE = 1 << 16; + + // Ensure there is a range of a power of 2 + static final int[] BOUNDS = {256}; + static final int[] ORIGINS = {-16, 0, 16}; + + static > ResultAsserter> randomAsserter(int size, T origin, T bound) { + return (act, exp, ord, par) -> { + int count = 0; + Set> values = new HashSet<>(); + for (Comparable t : act) { + if (origin.compareTo(bound) < 0) { + assertTrue(t.compareTo(origin) >= 0); + assertTrue(t.compareTo(bound) < 0); + } + values.add(t); + count++; + } + assertEquals(count, size); + // Assert that at least one different result is produced + // For the size of the data it is highly improbable that this + // will cause a false negative (i.e. a false failure) + assertTrue(values.size() > 1); + }; + } + + @DataProvider(name = "ints") + public static Object[][] intsDataProvider() { + List data = new ArrayList<>(); + + // Function to create a stream using a RandomBoxedSpliterator + + Function, IntStream> rbsf = + sf -> StreamSupport.stream(new RandomBoxedSpliterator<>(new SplittableRandom(), 0, SIZE, sf), false). + mapToInt(i -> i); + + // Unbounded + + data.add(new Object[]{ + TestData.Factory.ofIntSupplier( + String.format("new SplittableRandom().ints().limit(%d)", SIZE), + () -> new SplittableRandom().ints().limit(SIZE)), + randomAsserter(SIZE, Integer.MAX_VALUE, 0) + }); + + data.add(new Object[]{ + TestData.Factory.ofIntSupplier( + String.format("new SplittableRandom().ints(%d)", SIZE), + () -> new SplittableRandom().ints(SIZE)), + randomAsserter(SIZE, Integer.MAX_VALUE, 0) + }); + + data.add(new Object[]{ + TestData.Factory.ofIntSupplier( + String.format("new RandomBoxedSpliterator(0, %d, sr -> sr.nextInt())", SIZE), + () -> rbsf.apply(sr -> sr.nextInt())), + randomAsserter(SIZE, Integer.MAX_VALUE, 0) + }); + + // Bounded + + for (int b : BOUNDS) { + for (int o : ORIGINS) { + final int origin = o; + final int bound = b; + + data.add(new Object[]{ + TestData.Factory.ofIntSupplier( + String.format("new SplittableRandom().ints(%d, %d).limit(%d)", origin, bound, SIZE), + () -> new SplittableRandom().ints(origin, bound).limit(SIZE)), + randomAsserter(SIZE, origin, bound) + }); + + data.add(new Object[]{ + TestData.Factory.ofIntSupplier( + String.format("new SplittableRandom().ints(%d, %d, %d)", SIZE, origin, bound), + () -> new SplittableRandom().ints(SIZE, origin, bound)), + randomAsserter(SIZE, origin, bound) + }); + + if (origin == 0) { + data.add(new Object[]{ + TestData.Factory.ofIntSupplier( + String.format("new RandomBoxedSpliterator(0, %d, sr -> sr.nextInt(%d))", SIZE, bound), + () -> rbsf.apply(sr -> sr.nextInt(bound))), + randomAsserter(SIZE, origin, bound) + }); + } + + data.add(new Object[]{ + TestData.Factory.ofIntSupplier( + String.format("new RandomBoxedSpliterator(0, %d, sr -> sr.nextInt(%d, %d))", SIZE, origin, bound), + () -> rbsf.apply(sr -> sr.nextInt(origin, bound))), + randomAsserter(SIZE, origin, bound) + }); + } + } + + return data.toArray(new Object[0][]); + } + + @Test(dataProvider = "ints") + public void testInts(TestData.OfInt data, ResultAsserter> ra) { + withData(data). + stream(s -> s). + without(IntStreamTestScenario.PAR_STREAM_TO_ARRAY_CLEAR_SIZED). + resultAsserter(ra). + exercise(); + } + + @DataProvider(name = "longs") + public static Object[][] longsDataProvider() { + List data = new ArrayList<>(); + + // Function to create a stream using a RandomBoxedSpliterator + + Function, LongStream> rbsf = + sf -> StreamSupport.stream(new RandomBoxedSpliterator<>(new SplittableRandom(), 0, SIZE, sf), false). + mapToLong(i -> i); + + // Unbounded + + data.add(new Object[]{ + TestData.Factory.ofLongSupplier( + String.format("new SplittableRandom().longs().limit(%d)", SIZE), + () -> new SplittableRandom().longs().limit(SIZE)), + randomAsserter(SIZE, Long.MAX_VALUE, 0L) + }); + + data.add(new Object[]{ + TestData.Factory.ofLongSupplier( + String.format("new SplittableRandom().longs(%d)", SIZE), + () -> new SplittableRandom().longs(SIZE)), + randomAsserter(SIZE, Long.MAX_VALUE, 0L) + }); + + data.add(new Object[]{ + TestData.Factory.ofLongSupplier( + String.format("new RandomBoxedSpliterator(0, %d, sr -> sr.nextLong())", SIZE), + () -> rbsf.apply(sr -> sr.nextLong())), + randomAsserter(SIZE, Long.MAX_VALUE, 0L) + }); + + // Bounded + + for (int b : BOUNDS) { + for (int o : ORIGINS) { + final long origin = o; + final long bound = b; + + data.add(new Object[]{ + TestData.Factory.ofLongSupplier( + String.format("new SplittableRandom().longs(%d, %d).limit(%d)", origin, bound, SIZE), + () -> new SplittableRandom().longs(origin, bound).limit(SIZE)), + randomAsserter(SIZE, origin, bound) + }); + + data.add(new Object[]{ + TestData.Factory.ofLongSupplier( + String.format("new SplittableRandom().longs(%d, %d, %d)", SIZE, origin, bound), + () -> new SplittableRandom().longs(SIZE, origin, bound)), + randomAsserter(SIZE, origin, bound) + }); + + if (origin == 0) { + data.add(new Object[]{ + TestData.Factory.ofLongSupplier( + String.format("new RandomBoxedSpliterator(0, %d, sr -> sr.nextLong(%d))", SIZE, bound), + () -> rbsf.apply(sr -> sr.nextLong(bound))), + randomAsserter(SIZE, origin, bound) + }); + } + + data.add(new Object[]{ + TestData.Factory.ofLongSupplier( + String.format("new RandomBoxedSpliterator(0, %d, sr -> sr.nextLong(%d, %d))", SIZE, origin, bound), + () -> rbsf.apply(sr -> sr.nextLong(origin, bound))), + randomAsserter(SIZE, origin, bound) + }); + } + } + + return data.toArray(new Object[0][]); + } + + @Test(dataProvider = "longs") + public void testLongs(TestData.OfLong data, ResultAsserter> ra) { + withData(data). + stream(s -> s). + without(LongStreamTestScenario.PAR_STREAM_TO_ARRAY_CLEAR_SIZED). + resultAsserter(ra). + exercise(); + } + + @DataProvider(name = "doubles") + public static Object[][] doublesDataProvider() { + List data = new ArrayList<>(); + + // Function to create a stream using a RandomBoxedSpliterator + + Function, DoubleStream> rbsf = + sf -> StreamSupport.stream(new RandomBoxedSpliterator<>(new SplittableRandom(), 0, SIZE, sf), false). + mapToDouble(i -> i); + + // Unbounded + + data.add(new Object[]{ + TestData.Factory.ofDoubleSupplier( + String.format("new SplittableRandom().doubles().limit(%d)", SIZE), + () -> new SplittableRandom().doubles().limit(SIZE)), + randomAsserter(SIZE, Double.MAX_VALUE, 0d) + }); + + data.add(new Object[]{ + TestData.Factory.ofDoubleSupplier( + String.format("new SplittableRandom().doubles(%d)", SIZE), + () -> new SplittableRandom().doubles(SIZE)), + randomAsserter(SIZE, Double.MAX_VALUE, 0d) + }); + + data.add(new Object[]{ + TestData.Factory.ofDoubleSupplier( + String.format("new RandomBoxedSpliterator(0, %d, sr -> sr.nextDouble())", SIZE), + () -> rbsf.apply(sr -> sr.nextDouble())), + randomAsserter(SIZE, Double.MAX_VALUE, 0d) + }); + + // Bounded + + for (int b : BOUNDS) { + for (int o : ORIGINS) { + final double origin = o; + final double bound = b; + + data.add(new Object[]{ + TestData.Factory.ofDoubleSupplier( + String.format("new SplittableRandom().doubles(%f, %f).limit(%d)", origin, bound, SIZE), + () -> new SplittableRandom().doubles(origin, bound).limit(SIZE)), + randomAsserter(SIZE, origin, bound) + }); + + data.add(new Object[]{ + TestData.Factory.ofDoubleSupplier( + String.format("new SplittableRandom().doubles(%d, %f, %f)", SIZE, origin, bound), + () -> new SplittableRandom().doubles(SIZE, origin, bound)), + randomAsserter(SIZE, origin, bound) + }); + + if (origin == 0) { + data.add(new Object[]{ + TestData.Factory.ofDoubleSupplier( + String.format("new RandomBoxedSpliterator(0, %d, sr -> sr.nextDouble(%f))", SIZE, bound), + () -> rbsf.apply(sr -> sr.nextDouble(bound))), + randomAsserter(SIZE, origin, bound) + }); + } + + data.add(new Object[]{ + TestData.Factory.ofDoubleSupplier( + String.format("new RandomBoxedSpliterator(0, %d, sr -> sr.nextDouble(%f, %f))", SIZE, origin, bound), + () -> rbsf.apply(sr -> sr.nextDouble(origin, bound))), + randomAsserter(SIZE, origin, bound) + }); + } + } + + return data.toArray(new Object[0][]); + } + + @Test(dataProvider = "doubles") + public void testDoubles(TestData.OfDouble data, ResultAsserter> ra) { + withData(data). + stream(s -> s). + without(DoubleStreamTestScenario.PAR_STREAM_TO_ARRAY_CLEAR_SIZED). + resultAsserter(ra). + exercise(); + } +} From 849788a425dcccfded4905f701d487773826751e Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 27 Aug 2013 17:50:52 +0800 Subject: [PATCH 31/44] 8015669: KerberosPrincipal::equals should ignore name-type Reviewed-by: mullan --- .../auth/kerberos/KerberosPrincipal.java | 14 ++--- jdk/test/sun/security/krb5/auto/KPEquals.java | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 jdk/test/sun/security/krb5/auto/KPEquals.java diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java b/jdk/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java index 6962f2a43d3..1c033803cc7 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java @@ -197,8 +197,7 @@ public final class KerberosPrincipal * {@code KerberosPrincipal} and the two * {@code KerberosPrincipal} instances are equivalent. * More formally two {@code KerberosPrincipal} instances are equal - * if the values returned by {@code getName()} are equal and the - * values returned by {@code getNameType()} are equal. + * if the values returned by {@code getName()} are equal. * * @param other the Object to compare to * @return true if the Object passed in represents the same principal @@ -211,15 +210,10 @@ public final class KerberosPrincipal if (! (other instanceof KerberosPrincipal)) { return false; - } else { - String myFullName = getName(); - String otherFullName = ((KerberosPrincipal) other).getName(); - if (nameType == ((KerberosPrincipal)other).nameType && - myFullName.equals(otherFullName)) { - return true; - } } - return false; + String myFullName = getName(); + String otherFullName = ((KerberosPrincipal) other).getName(); + return myFullName.equals(otherFullName); } /** diff --git a/jdk/test/sun/security/krb5/auto/KPEquals.java b/jdk/test/sun/security/krb5/auto/KPEquals.java new file mode 100644 index 00000000000..7a7aaa34f24 --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/KPEquals.java @@ -0,0 +1,55 @@ +/* + * 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 8015669 + * @summary KerberosPrincipal::equals should ignore name-type + * @compile -XDignore.symbol.file KPEquals.java + * @run main/othervm KPEquals + */ + +import sun.security.jgss.GSSUtil; + +import javax.security.auth.kerberos.KerberosKey; +import javax.security.auth.kerberos.KerberosPrincipal; +import javax.security.auth.kerberos.KeyTab; + +public class KPEquals { + + public static void main(String[] args) throws Exception { + new OneKDC(null).writeJAASConf(); + Context c = Context.fromJAAS("client"); + Context s = Context.fromThinAir(); + KerberosPrincipal kp = new KerberosPrincipal( + OneKDC.SERVER + "@" + OneKDC.REALM, + KerberosPrincipal.KRB_NT_SRV_INST); + s.s().getPrincipals().add(kp); + for (KerberosKey k: KeyTab.getInstance(kp).getKeys(kp)) { + s.s().getPrivateCredentials().add(k); + } + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + } +} From c5fd247e16d75945a5940f2a57f2f2e4febb3dbe Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 27 Aug 2013 17:50:55 +0800 Subject: [PATCH 32/44] 8022761: regression: SecurityException is NOT thrown while trying to pack a wrongly signed Indexed Jar file Reviewed-by: sherman --- .../classes/java/util/jar/JarVerifier.java | 4 +- .../sun/security/tools/jarsigner/jvindex.sh | 76 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 jdk/test/sun/security/tools/jarsigner/jvindex.sh diff --git a/jdk/src/share/classes/java/util/jar/JarVerifier.java b/jdk/src/share/classes/java/util/jar/JarVerifier.java index 73748c1083d..30459e54324 100644 --- a/jdk/src/share/classes/java/util/jar/JarVerifier.java +++ b/jdk/src/share/classes/java/util/jar/JarVerifier.java @@ -32,6 +32,7 @@ import java.security.*; import java.security.cert.CertificateException; import java.util.zip.ZipEntry; +import sun.misc.JarIndex; import sun.security.util.ManifestDigester; import sun.security.util.ManifestEntryVerifier; import sun.security.util.SignatureFileVerifier; @@ -139,7 +140,8 @@ class JarVerifier { return; } - if (uname.equals(JarFile.MANIFEST_NAME)) { + if (uname.equals(JarFile.MANIFEST_NAME) || + uname.equals(JarIndex.INDEX_NAME)) { return; } diff --git a/jdk/test/sun/security/tools/jarsigner/jvindex.sh b/jdk/test/sun/security/tools/jarsigner/jvindex.sh new file mode 100644 index 00000000000..c4435b68121 --- /dev/null +++ b/jdk/test/sun/security/tools/jarsigner/jvindex.sh @@ -0,0 +1,76 @@ +# +# 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 8022761 +# @summary regression: SecurityException is NOT thrown while trying to pack a wrongly signed Indexed Jar file +# + +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +F=abcde +KS=jvindex.jks +JFILE=jvindex.jar + +KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit \ + -keystore $KS" +JAR=$TESTJAVA${FS}bin${FS}jar +JARSIGNER="$TESTJAVA${FS}bin${FS}jarsigner -keystore $KS -storepass changeit" + +rm $F $KS $JFILE 2> /dev/null + +echo 12345 > $F +$JAR cvf $JFILE $F + +ERR="" + +$KT -alias a -dname CN=a -genkey -validity 300 || ERR="$ERR 1" + +$JARSIGNER $JFILE a || ERR="$ERR 2" +$JAR i $JFILE + +# Make sure the $F line has "sm" (signed and in manifest) +$JARSIGNER -verify -verbose $JFILE | grep $F | grep sm || ERR="$ERR 3" + +if [ "$ERR" = "" ]; then + exit 0 +else + echo "ERR is $ERR" + exit 1 +fi + + From 05f2952a67a9b88e0283dbe3796e967d449cc688 Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Tue, 27 Aug 2013 10:46:03 -0400 Subject: [PATCH 33/44] 8023769: JDK-8016850 broke the old build Remove files that were moved/removed from com/sun/security/auth/FILES_java.gmk Reviewed-by: chegar, xuelei --- jdk/make/com/sun/security/auth/FILES_java.gmk | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/jdk/make/com/sun/security/auth/FILES_java.gmk b/jdk/make/com/sun/security/auth/FILES_java.gmk index 3e96e9d58b3..fa4f7d4b8d0 100644 --- a/jdk/make/com/sun/security/auth/FILES_java.gmk +++ b/jdk/make/com/sun/security/auth/FILES_java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 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 @@ -43,8 +43,6 @@ FILES_java = \ com/sun/security/auth/UserPrincipal.java \ com/sun/security/auth/LdapPrincipal.java \ com/sun/security/auth/PolicyFile.java \ - com/sun/security/auth/SubjectCodeSource.java \ - com/sun/security/auth/PolicyParser.java \ com/sun/security/auth/PrincipalComparator.java \ com/sun/security/auth/callback/TextCallbackHandler.java \ com/sun/security/auth/callback/DialogCallbackHandler.java From 4520fbf9834fceedb35b806b1effe3417f2d7ce7 Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Tue, 27 Aug 2013 12:04:32 -0400 Subject: [PATCH 34/44] 8019830: Add com.sun.media.sound to the list of restricted package Reviewed-by: vinnie --- jdk/src/share/lib/security/java.security-linux | 2 ++ jdk/src/share/lib/security/java.security-macosx | 2 ++ jdk/src/share/lib/security/java.security-solaris | 2 ++ jdk/src/share/lib/security/java.security-windows | 2 ++ jdk/test/java/lang/SecurityManager/CheckPackageAccess.java | 3 ++- 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux index 2686cae4c4f..2c5f5f6c32a 100644 --- a/jdk/src/share/lib/security/java.security-linux +++ b/jdk/src/share/lib/security/java.security-linux @@ -181,6 +181,7 @@ package.access=sun.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ + com.sun.media.sound.,\ com.sun.proxy.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ @@ -225,6 +226,7 @@ package.definition=sun.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ + com.sun.media.sound.,\ com.sun.proxy.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index 7ea2ee18735..44791b241f4 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -182,6 +182,7 @@ package.access=sun.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ + com.sun.media.sound.,\ com.sun.proxy.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ @@ -226,6 +227,7 @@ package.definition=sun.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ + com.sun.media.sound.,\ com.sun.proxy.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index be885d3b187..a6ce253df8a 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -183,6 +183,7 @@ package.access=sun.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ + com.sun.media.sound.,\ com.sun.proxy.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ @@ -226,6 +227,7 @@ package.definition=sun.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ + com.sun.media.sound.,\ com.sun.proxy.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index c06a56156ae..cca53ae3961 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -182,6 +182,7 @@ package.access=sun.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ + com.sun.media.sound.,\ com.sun.proxy.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ @@ -226,6 +227,7 @@ package.definition=sun.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ + com.sun.media.sound.,\ com.sun.proxy.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ diff --git a/jdk/test/java/lang/SecurityManager/CheckPackageAccess.java b/jdk/test/java/lang/SecurityManager/CheckPackageAccess.java index 7167bbb96c8..c6b9a1e59be 100644 --- a/jdk/test/java/lang/SecurityManager/CheckPackageAccess.java +++ b/jdk/test/java/lang/SecurityManager/CheckPackageAccess.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6741606 7146431 8000450 + * @bug 6741606 7146431 8000450 8019830 * @summary Make sure all restricted packages listed in the package.access * property in the java.security file are blocked * @run main/othervm CheckPackageAccess @@ -54,6 +54,7 @@ public class CheckPackageAccess { "com.sun.imageio.", "com.sun.istack.internal.", "com.sun.jmx.", + "com.sun.media.sound.", "com.sun.proxy.", "com.sun.org.apache.bcel.internal.", "com.sun.org.apache.regexp.internal.", From ab9f31ab536a49a91c58abfaef3f8f91777058b5 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 27 Aug 2013 11:46:25 -0700 Subject: [PATCH 35/44] 8023827: Fix doclint issues in javax.net.ssl Reviewed-by: wetmore, xuelei --- jdk/src/share/classes/javax/net/ssl/SNIHostName.java | 3 ++- jdk/src/share/classes/javax/net/ssl/X509KeyManager.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/javax/net/ssl/SNIHostName.java b/jdk/src/share/classes/javax/net/ssl/SNIHostName.java index 588a8547e11..d5e71414497 100644 --- a/jdk/src/share/classes/javax/net/ssl/SNIHostName.java +++ b/jdk/src/share/classes/javax/net/ssl/SNIHostName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -293,6 +293,7 @@ public final class SNIHostName extends SNIServerName { * the * regular expression pattern * representing the hostname(s) to match + * @return a {@code SNIMatcher} object for {@code SNIHostName}s * @throws NullPointerException if {@code regex} is * {@code null} * @throws java.util.regex.PatternSyntaxException if the regular expression's diff --git a/jdk/src/share/classes/javax/net/ssl/X509KeyManager.java b/jdk/src/share/classes/javax/net/ssl/X509KeyManager.java index 5174adfe412..69ab91ae94d 100644 --- a/jdk/src/share/classes/javax/net/ssl/X509KeyManager.java +++ b/jdk/src/share/classes/javax/net/ssl/X509KeyManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -40,7 +40,7 @@ import java.net.Socket; *

    *
  • determine the set of aliases that are available for negotiations * based on the criteria presented, - *
  • select the best alias based on + *
  • select the best alias based on * the criteria presented, and *
  • obtain the corresponding key material for given aliases. *
From b87db568f08306339fb64c78c43a418da5051e41 Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Mon, 26 Aug 2013 22:32:50 -0700 Subject: [PATCH 36/44] 8023275: Wrapping collections should override default methods Reviewed-by: mduigou, psandoz --- .../share/classes/java/util/Collections.java | 57 ++++++- jdk/test/java/util/Collections/Wrappers.java | 146 ++++++++++++++++++ 2 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 jdk/test/java/util/Collections/Wrappers.java diff --git a/jdk/src/share/classes/java/util/Collections.java b/jdk/src/share/classes/java/util/Collections.java index 16263277f70..2404b4fc9ad 100644 --- a/jdk/src/share/classes/java/util/Collections.java +++ b/jdk/src/share/classes/java/util/Collections.java @@ -27,7 +27,6 @@ package java.util; import java.io.Serializable; import java.io.ObjectOutputStream; import java.io.IOException; -import java.io.InvalidObjectException; import java.lang.reflect.Array; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -35,6 +34,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; +import java.util.stream.IntStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -1148,7 +1148,16 @@ public class Collections { public Spliterator spliterator() { return (Spliterator)c.spliterator(); } - + @SuppressWarnings("unchecked") + @Override + public Stream stream() { + return (Stream)c.stream(); + } + @SuppressWarnings("unchecked") + @Override + public Stream parallelStream() { + return (Stream)c.parallelStream(); + } } /** @@ -2009,8 +2018,8 @@ public class Collections { * through the returned collection.

* * It is imperative that the user manually synchronize on the returned - * collection when traversing it via {@link Iterator} or - * {@link Spliterator}: + * collection when traversing it via {@link Iterator}, {@link Spliterator} + * or {@link Stream}: *

      *  Collection c = Collections.synchronizedCollection(myCollection);
      *     ...
@@ -2120,6 +2129,14 @@ public class Collections {
         public Spliterator spliterator() {
             return c.spliterator(); // Must be manually synched by user!
         }
+        @Override
+        public Stream stream() {
+            return c.stream(); // Must be manually synched by user!
+        }
+        @Override
+        public Stream parallelStream() {
+            return c.parallelStream(); // Must be manually synched by user!
+        }
         private void writeObject(ObjectOutputStream s) throws IOException {
             synchronized (mutex) {s.defaultWriteObject();}
         }
@@ -3172,6 +3189,10 @@ public class Collections {
         }
         @Override
         public Spliterator spliterator() {return c.spliterator();}
+        @Override
+        public Stream stream()           {return c.stream();}
+        @Override
+        public Stream parallelStream()   {return c.parallelStream();}
     }
 
     /**
@@ -5096,6 +5117,22 @@ public class Collections {
                                                    ") > toIndex(" + toIndex + ")");
             return new CopiesList<>(toIndex - fromIndex, element);
         }
+
+        // Override default methods in Collection
+        @Override
+        public Stream stream() {
+            return IntStream.range(0, n).mapToObj(i -> element);
+        }
+
+        @Override
+        public Stream parallelStream() {
+            return IntStream.range(0, n).parallel().mapToObj(i -> element);
+        }
+
+        @Override
+        public Spliterator spliterator() {
+            return stream().spliterator();
+        }
     }
 
     /**
@@ -5503,6 +5540,10 @@ public class Collections {
 
         @Override
         public Spliterator spliterator() {return s.spliterator();}
+        @Override
+        public Stream stream()           {return s.stream();}
+        @Override
+        public Stream parallelStream()   {return s.parallelStream();}
 
         private static final long serialVersionUID = 2454657854757543876L;
 
@@ -5568,10 +5609,14 @@ public class Collections {
         @Override
         public void forEach(Consumer action) {q.forEach(action);}
         @Override
-        public Spliterator spliterator() {return q.spliterator();}
-        @Override
         public boolean removeIf(Predicate filter) {
             return q.removeIf(filter);
         }
+        @Override
+        public Spliterator spliterator() {return q.spliterator();}
+        @Override
+        public Stream stream()           {return q.stream();}
+        @Override
+        public Stream parallelStream()   {return q.parallelStream();}
     }
 }
diff --git a/jdk/test/java/util/Collections/Wrappers.java b/jdk/test/java/util/Collections/Wrappers.java
new file mode 100644
index 00000000000..3882a4efdd1
--- /dev/null
+++ b/jdk/test/java/util/Collections/Wrappers.java
@@ -0,0 +1,146 @@
+/*
+ * 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
+ * @run testng Wrappers
+ * @summary Ensure Collections wrapping classes provide non-default implementations
+ */
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+import static org.testng.Assert.assertFalse;
+
+@Test(groups = "unit")
+public class Wrappers {
+    static Object[][] collections;
+
+    @DataProvider(name="collections")
+    public static Object[][] collectionCases() {
+        if (collections != null) {
+            return collections;
+        }
+
+        List cases = new ArrayList<>();
+        LinkedList seedList = new LinkedList<>();
+        ArrayList seedRandomAccess = new ArrayList<>();
+        TreeSet seedSet = new TreeSet<>();
+        TreeMap seedMap = new TreeMap<>();
+
+        for (int i = 1; i <= 10; i++) {
+            seedList.add(i);
+            seedRandomAccess.add(i);
+            seedSet.add(i);
+            seedMap.put(i, i);
+        }
+
+        cases.add(new Object[] { Collections.unmodifiableCollection(seedList) });
+        cases.add(new Object[] { Collections.unmodifiableList(seedList) });
+        cases.add(new Object[] { Collections.unmodifiableList(seedRandomAccess) });
+        cases.add(new Object[] { Collections.unmodifiableSet(seedSet) });
+        cases.add(new Object[] { Collections.unmodifiableSortedSet(seedSet) });
+        cases.add(new Object[] { Collections.unmodifiableNavigableSet(seedSet) });
+
+        // As sets from map also need to be unmodifiable, thus a wrapping
+        // layer exist and should not have default methods
+        cases.add(new Object[] { Collections.unmodifiableMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.unmodifiableMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.unmodifiableMap(seedMap).values() });
+        cases.add(new Object[] { Collections.unmodifiableSortedMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.unmodifiableSortedMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.unmodifiableSortedMap(seedMap).values() });
+        cases.add(new Object[] { Collections.unmodifiableNavigableMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.unmodifiableNavigableMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.unmodifiableNavigableMap(seedMap).values() });
+
+        // Synchronized
+        cases.add(new Object[] { Collections.synchronizedCollection(seedList) });
+        cases.add(new Object[] { Collections.synchronizedList(seedList) });
+        cases.add(new Object[] { Collections.synchronizedList(seedRandomAccess) });
+        cases.add(new Object[] { Collections.synchronizedSet(seedSet) });
+        cases.add(new Object[] { Collections.synchronizedSortedSet(seedSet) });
+        cases.add(new Object[] { Collections.synchronizedNavigableSet(seedSet) });
+
+        // As sets from map also need to be synchronized on the map, thus a
+        // wrapping layer exist and should not have default methods
+        cases.add(new Object[] { Collections.synchronizedMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.synchronizedMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.synchronizedMap(seedMap).values() });
+        cases.add(new Object[] { Collections.synchronizedSortedMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.synchronizedSortedMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.synchronizedSortedMap(seedMap).values() });
+        cases.add(new Object[] { Collections.synchronizedNavigableMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.synchronizedNavigableMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.synchronizedNavigableMap(seedMap).values() });
+
+        // Checked
+        cases.add(new Object[] { Collections.checkedCollection(seedList, Integer.class) });
+        cases.add(new Object[] { Collections.checkedList(seedList, Integer.class) });
+        cases.add(new Object[] { Collections.checkedList(seedRandomAccess, Integer.class) });
+        cases.add(new Object[] { Collections.checkedSet(seedSet, Integer.class) });
+        cases.add(new Object[] { Collections.checkedSortedSet(seedSet, Integer.class) });
+        cases.add(new Object[] { Collections.checkedNavigableSet(seedSet, Integer.class) });
+        cases.add(new Object[] { Collections.checkedQueue(seedList, Integer.class) });
+
+        // asLifoQueue is another wrapper
+        cases.add(new Object[] { Collections.asLifoQueue(seedList) });
+
+        collections = cases.toArray(new Object[0][]);
+        return collections;
+    }
+
+    static Method[] defaultMethods;
+
+    static {
+        List list = new ArrayList<>();
+        Method[] methods = Collection.class.getMethods();
+        for (Method m: methods) {
+            if (m.isDefault()) {
+                list.add(m);
+            }
+        }
+        defaultMethods = list.toArray(new Method[0]);
+    }
+
+    @Test(dataProvider = "collections")
+    public static void testAllDefaultMethodsOverridden(Collection c) throws NoSuchMethodException {
+        Class cls = c.getClass();
+        for (Method m: defaultMethods) {
+            Method m2 = cls.getMethod(m.getName(), m.getParameterTypes());
+            // default had been override
+            assertFalse(m2.isDefault(), cls.getCanonicalName());
+        }
+    }
+}
+

From d912aa501eb2b51ae468b01e1bb535365d999473 Mon Sep 17 00:00:00 2001
From: Xueming Shen 
Date: Tue, 27 Aug 2013 12:54:44 -0700
Subject: [PATCH 37/44] 8023647: "abc1c".matches("(\\w)+1\\1")) returns false

To correct the wrong GroupCurly group index backoff code

Reviewed-by: alanb
---
 jdk/src/share/classes/java/util/regex/Pattern.java |  6 ++----
 jdk/test/java/util/regex/RegExTest.java            | 12 +++++++++++-
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/jdk/src/share/classes/java/util/regex/Pattern.java b/jdk/src/share/classes/java/util/regex/Pattern.java
index 4eedd34c72a..1dc72c10cd3 100644
--- a/jdk/src/share/classes/java/util/regex/Pattern.java
+++ b/jdk/src/share/classes/java/util/regex/Pattern.java
@@ -4456,16 +4456,16 @@ loop:   for(int x=0, offset=0; x p = Pattern.compile("[a-z]+").asPredicate();

From 1d19a4f5df8085a57cea8acc5d8c5c9327dfaeff Mon Sep 17 00:00:00 2001
From: Henry Jen 
Date: Wed, 21 Aug 2013 20:41:35 -0700
Subject: [PATCH 38/44] 8023528: Rename Comparator combinators to disambiguate
 overloading methods

Reviewed-by: mduigou, smarks
---
 .../share/classes/java/util/Comparator.java   | 32 +++++++-------
 jdk/test/java/util/Comparator/BasicTest.java  | 42 +++++++++----------
 jdk/test/java/util/Map/EntryComparators.java  |  4 +-
 .../function/BinaryOperator/BasicTest.java    | 14 +++----
 4 files changed, 46 insertions(+), 46 deletions(-)

diff --git a/jdk/src/share/classes/java/util/Comparator.java b/jdk/src/share/classes/java/util/Comparator.java
index 55d5efb9866..b19481df198 100644
--- a/jdk/src/share/classes/java/util/Comparator.java
+++ b/jdk/src/share/classes/java/util/Comparator.java
@@ -199,7 +199,7 @@ public interface Comparator {
      * composed using following code,
      *
      * 
{@code
-     *     Comparator cmp = Comparator.comparing(String::length)
+     *     Comparator cmp = Comparator.comparingInt(String::length)
      *             .thenComparing(String.CASE_INSENSITIVE_ORDER);
      * }
* @@ -270,18 +270,18 @@ public interface Comparator { * extracts a {@code int} sort key. * * @implSpec This default implementation behaves as if {@code - * thenComparing(comparing(keyExtractor))}. + * thenComparing(comparingInt(keyExtractor))}. * * @param keyExtractor the function used to extract the integer sort key * @return a lexicographic-order comparator composed of this and then the * {@code int} sort key * @throws NullPointerException if the argument is null. - * @see #comparing(ToIntFunction) + * @see #comparingInt(ToIntFunction) * @see #thenComparing(Comparator) * @since 1.8 */ - default Comparator thenComparing(ToIntFunction keyExtractor) { - return thenComparing(comparing(keyExtractor)); + default Comparator thenComparingInt(ToIntFunction keyExtractor) { + return thenComparing(comparingInt(keyExtractor)); } /** @@ -289,18 +289,18 @@ public interface Comparator { * extracts a {@code long} sort key. * * @implSpec This default implementation behaves as if {@code - * thenComparing(comparing(keyExtractor))}. + * thenComparing(comparingLong(keyExtractor))}. * * @param keyExtractor the function used to extract the long sort key * @return a lexicographic-order comparator composed of this and then the * {@code long} sort key * @throws NullPointerException if the argument is null. - * @see #comparing(ToLongFunction) + * @see #comparingLong(ToLongFunction) * @see #thenComparing(Comparator) * @since 1.8 */ - default Comparator thenComparing(ToLongFunction keyExtractor) { - return thenComparing(comparing(keyExtractor)); + default Comparator thenComparingLong(ToLongFunction keyExtractor) { + return thenComparing(comparingLong(keyExtractor)); } /** @@ -308,18 +308,18 @@ public interface Comparator { * extracts a {@code double} sort key. * * @implSpec This default implementation behaves as if {@code - * thenComparing(comparing(keyExtractor))}. + * thenComparing(comparingDouble(keyExtractor))}. * * @param keyExtractor the function used to extract the double sort key * @return a lexicographic-order comparator composed of this and then the * {@code double} sort key * @throws NullPointerException if the argument is null. - * @see #comparing(ToDoubleFunction) + * @see #comparingDouble(ToDoubleFunction) * @see #thenComparing(Comparator) * @since 1.8 */ - default Comparator thenComparing(ToDoubleFunction keyExtractor) { - return thenComparing(comparing(keyExtractor)); + default Comparator thenComparingDouble(ToDoubleFunction keyExtractor) { + return thenComparing(comparingDouble(keyExtractor)); } /** @@ -484,7 +484,7 @@ public interface Comparator { * @throws NullPointerException if the argument is null * @since 1.8 */ - public static Comparator comparing(ToIntFunction keyExtractor) { + public static Comparator comparingInt(ToIntFunction keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); @@ -505,7 +505,7 @@ public interface Comparator { * @throws NullPointerException if the argument is null * @since 1.8 */ - public static Comparator comparing(ToLongFunction keyExtractor) { + public static Comparator comparingLong(ToLongFunction keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); @@ -526,7 +526,7 @@ public interface Comparator { * @throws NullPointerException if the argument is null * @since 1.8 */ - public static Comparator comparing(ToDoubleFunction keyExtractor) { + public static Comparator comparingDouble(ToDoubleFunction keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2)); diff --git a/jdk/test/java/util/Comparator/BasicTest.java b/jdk/test/java/util/Comparator/BasicTest.java index 5bbb700e0b3..b4eb5d4ac40 100644 --- a/jdk/test/java/util/Comparator/BasicTest.java +++ b/jdk/test/java/util/Comparator/BasicTest.java @@ -90,7 +90,7 @@ public class BasicTest { Thing[] things = new Thing[intValues.length]; for (int i=0; i comp = Comparator.comparing(new ToIntFunction() { + Comparator comp = Comparator.comparingInt(new ToIntFunction() { @Override public int applyAsInt(Thing thing) { return thing.getIntField(); @@ -104,7 +104,7 @@ public class BasicTest { Thing[] things = new Thing[longValues.length]; for (int i=0; i comp = Comparator.comparing(new ToLongFunction() { + Comparator comp = Comparator.comparingLong(new ToLongFunction() { @Override public long applyAsLong(Thing thing) { return thing.getLongField(); @@ -118,7 +118,7 @@ public class BasicTest { Thing[] things = new Thing[doubleValues.length]; for (int i=0; i comp = Comparator.comparing(new ToDoubleFunction() { + Comparator comp = Comparator.comparingDouble(new ToDoubleFunction() { @Override public double applyAsDouble(Thing thing) { return thing.getDoubleField(); @@ -211,8 +211,8 @@ public class BasicTest { }; public void testComparatorDefaultMethods() { - Comparator cmp = Comparator.comparing((Function) People::getFirstName); - Comparator cmp2 = Comparator.comparing((Function) People::getLastName); + Comparator cmp = Comparator.comparing(People::getFirstName); + Comparator cmp2 = Comparator.comparing(People::getLastName); // reverseOrder assertComparison(cmp.reversed(), people[1], people[0]); // thenComparing(Comparator) @@ -222,20 +222,20 @@ public class BasicTest { assertComparison(cmp.thenComparing(People::getLastName), people[0], people[1]); assertComparison(cmp.thenComparing(People::getLastName), people[4], people[0]); // thenComparing(ToIntFunction) - assertComparison(cmp.thenComparing(People::getAge), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getAge), people[1], people[5]); + assertComparison(cmp.thenComparingInt(People::getAge), people[0], people[1]); + assertComparison(cmp.thenComparingInt(People::getAge), people[1], people[5]); // thenComparing(ToLongFunction) - assertComparison(cmp.thenComparing(People::getAgeAsLong), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getAgeAsLong), people[1], people[5]); + assertComparison(cmp.thenComparingLong(People::getAgeAsLong), people[0], people[1]); + assertComparison(cmp.thenComparingLong(People::getAgeAsLong), people[1], people[5]); // thenComparing(ToDoubleFunction) - assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[1], people[5]); + assertComparison(cmp.thenComparingDouble(People::getAgeAsDouble), people[0], people[1]); + assertComparison(cmp.thenComparingDouble(People::getAgeAsDouble), people[1], people[5]); } public void testNullsFirst() { Comparator strcmp = Comparator.nullsFirst(Comparator.naturalOrder()); - Comparator cmp = Comparator.comparing(People::getLastName, strcmp) + Comparator cmp = Comparator.comparing(People::getLastName, strcmp) .thenComparing(People::getFirstName, strcmp); // Mary.null vs Mary.Cook - solve by last name assertComparison(cmp, people[6], people[5]); @@ -243,7 +243,7 @@ public class BasicTest { assertComparison(cmp, people[7], people[6]); // More than one thenComparing - strcmp = Comparator.nullsFirst(Comparator.comparing((ToIntFunction) String::length) + strcmp = Comparator.nullsFirst(Comparator.comparingInt(String::length) .thenComparing(String.CASE_INSENSITIVE_ORDER)); assertComparison(strcmp, null, "abc"); assertComparison(strcmp, "ab", "abc"); @@ -273,7 +273,7 @@ public class BasicTest { public void testNullsLast() { Comparator strcmp = Comparator.nullsLast(Comparator.naturalOrder()); - Comparator cmp = Comparator.comparing(People::getLastName, strcmp) + Comparator cmp = Comparator.comparing(People::getLastName, strcmp) .thenComparing(People::getFirstName, strcmp); // Mary.null vs Mary.Cook - solve by last name assertComparison(cmp, people[5], people[6]); @@ -281,7 +281,7 @@ public class BasicTest { assertComparison(cmp, people[7], people[6]); // More than one thenComparing - strcmp = Comparator.nullsLast(Comparator.comparing((ToIntFunction) String::length) + strcmp = Comparator.nullsLast(Comparator.comparingInt(String::length) .thenComparing(String.CASE_INSENSITIVE_ORDER)); assertComparison(strcmp, "abc", null); assertComparison(strcmp, "ab", "abc"); @@ -341,28 +341,28 @@ public class BasicTest { } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((Function) null, Comparator.naturalOrder()); + Comparator cmp = Comparator.comparing(null, Comparator.naturalOrder()); fail("comparing(null, cmp) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((Function) People::getFirstName, null); + Comparator cmp = Comparator.comparing(People::getFirstName, null); fail("comparing(f, null) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((Function) null); + Comparator cmp = Comparator.comparing(null); fail("comparing(null) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((ToIntFunction) null); + Comparator cmp = Comparator.comparingInt(null); fail("comparing(null) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((ToLongFunction) null); + Comparator cmp = Comparator.comparingLong(null); fail("comparing(null) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((ToDoubleFunction) null); + Comparator cmp = Comparator.comparingDouble(null); fail("comparing(null) should throw NPE"); } catch (NullPointerException npe) {} } diff --git a/jdk/test/java/util/Map/EntryComparators.java b/jdk/test/java/util/Map/EntryComparators.java index ce607a36901..631107eada9 100644 --- a/jdk/test/java/util/Map/EntryComparators.java +++ b/jdk/test/java/util/Map/EntryComparators.java @@ -115,8 +115,8 @@ public class EntryComparators { // Comparator cmp = Comparator.naturalOrder(); // Should fail to compiler as People is not comparable // We can use simple comparator, but those have been tested above. // Thus choose to do compose for some level of interation. - Comparator cmp1 = Comparator.comparing((Function) People::getFirstName); - Comparator cmp2 = Comparator.comparing((Function) People::getLastName); + Comparator cmp1 = Comparator.comparing(People::getFirstName); + Comparator cmp2 = Comparator.comparing(People::getLastName); Comparator cmp = cmp1.thenComparing(cmp2); assertPairComparison(people[0], people[0], people[1], people[1], diff --git a/jdk/test/java/util/function/BinaryOperator/BasicTest.java b/jdk/test/java/util/function/BinaryOperator/BasicTest.java index 1519fb88177..0c37a9c5c62 100644 --- a/jdk/test/java/util/function/BinaryOperator/BasicTest.java +++ b/jdk/test/java/util/function/BinaryOperator/BasicTest.java @@ -67,26 +67,26 @@ public class BasicTest { }; public void testMaxBy() { - Comparator cmp = Comparator.comparing((Function) People::getFirstName); + Comparator cmp = Comparator.comparing(People::getFirstName); // lesser assertSame(maxBy(cmp).apply(people[0], people[1]), people[1]); // euqal - cmp = Comparator.comparing((Function) People::getLastName); + cmp = Comparator.comparing(People::getLastName); assertSame(maxBy(cmp).apply(people[0], people[1]), people[0]); // greater - cmp = Comparator.comparing((ToIntFunction) People::getAge); + cmp = Comparator.comparingInt(People::getAge); assertSame(maxBy(cmp).apply(people[0], people[1]), people[0]); } - public void testLesserOf() { - Comparator cmp = Comparator.comparing((Function) People::getFirstName); + public void testMinBy() { + Comparator cmp = Comparator.comparing(People::getFirstName); // lesser assertSame(minBy(cmp).apply(people[0], people[1]), people[0]); // euqal - cmp = Comparator.comparing((Function) People::getLastName); + cmp = Comparator.comparing(People::getLastName); assertSame(minBy(cmp).apply(people[0], people[1]), people[0]); // greater - cmp = Comparator.comparing((ToIntFunction) People::getAge); + cmp = Comparator.comparingInt(People::getAge); assertSame(minBy(cmp).apply(people[0], people[1]), people[1]); } From ce3943d27d9c6913335b7ba56f86905083522193 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Wed, 28 Aug 2013 14:07:30 +0100 Subject: [PATCH 39/44] 8023717: (process) ProcessBuilder should catch SecurityException rather than AccessControlException Reviewed-by: wetmore, alanb --- jdk/src/share/classes/java/lang/ProcessBuilder.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/java/lang/ProcessBuilder.java b/jdk/src/share/classes/java/lang/ProcessBuilder.java index 0cb7febe533..53fbc489a68 100644 --- a/jdk/src/share/classes/java/lang/ProcessBuilder.java +++ b/jdk/src/share/classes/java/lang/ProcessBuilder.java @@ -29,7 +29,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.security.AccessControlException; import java.util.Arrays; import java.util.ArrayList; import java.util.List; @@ -1033,9 +1032,9 @@ public final class ProcessBuilder // Can not disclose the fail reason for read-protected files. try { security.checkRead(prog); - } catch (AccessControlException ace) { + } catch (SecurityException se) { exceptionInfo = ""; - cause = ace; + cause = se; } } // It's much easier for us to create a high-quality error From 188f6e49f51c0b30b542ba5d80dacb39ef0919b0 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 28 Aug 2013 15:50:03 +0100 Subject: [PATCH 40/44] 8022594: Potential deadlock in of sun.nio.ch.Util/IOUtil Reviewed-by: chegar --- .../sun/nio/ch/KQueueArrayWrapper.java | 1 + .../sun/nio/ch/KQueueSelectorImpl.java | 5 ---- .../sun/nio/ch/AbstractPollSelectorImpl.java | 5 ---- .../sun/nio/ch/DatagramChannelImpl.java | 2 +- .../classes/sun/nio/ch/FileChannelImpl.java | 2 +- jdk/src/share/classes/sun/nio/ch/IOUtil.java | 18 +++++++++++-- jdk/src/share/classes/sun/nio/ch/Net.java | 2 +- .../sun/nio/ch/ServerSocketChannelImpl.java | 2 +- .../classes/sun/nio/ch/SocketChannelImpl.java | 2 +- jdk/src/share/classes/sun/nio/ch/Util.java | 26 ------------------- .../sun/nio/ch/DatagramDispatcher.java | 2 +- .../sun/nio/ch/DevPollArrayWrapper.java | 4 +++ .../sun/nio/ch/DevPollSelectorImpl.java | 5 ---- jdk/src/solaris/classes/sun/nio/ch/EPoll.java | 2 +- .../classes/sun/nio/ch/EPollArrayWrapper.java | 1 + .../solaris/classes/sun/nio/ch/EPollPort.java | 2 +- .../classes/sun/nio/ch/EPollSelectorImpl.java | 4 --- .../sun/nio/ch/FileDispatcherImpl.java | 2 +- .../classes/sun/nio/ch/InheritedChannel.java | 2 +- .../solaris/classes/sun/nio/ch/KQueue.java | 2 +- .../classes/sun/nio/ch/KQueuePort.java | 2 +- .../classes/sun/nio/ch/NativeThread.java | 2 +- .../classes/sun/nio/ch/PollArrayWrapper.java | 3 +++ .../classes/sun/nio/ch/SinkChannelImpl.java | 8 +----- .../classes/sun/nio/ch/SolarisEventPort.java | 2 +- .../classes/sun/nio/ch/SourceChannelImpl.java | 8 +----- ...ixAsynchronousServerSocketChannelImpl.java | 2 +- .../ch/UnixAsynchronousSocketChannelImpl.java | 2 +- .../sun/nio/ch/sctp/SctpChannelImpl.java | 2 +- .../sun/nio/ch/sctp/SctpMultiChannelImpl.java | 2 +- .../nio/ch/sctp/SctpServerChannelImpl.java | 2 +- .../sun/nio/ch/DatagramDispatcher.java | 2 +- .../sun/nio/ch/FileDispatcherImpl.java | 2 +- .../windows/classes/sun/nio/ch/FileKey.java | 1 + jdk/src/windows/classes/sun/nio/ch/Iocp.java | 2 +- .../windows/classes/sun/nio/ch/PipeImpl.java | 1 - .../classes/sun/nio/ch/SocketDispatcher.java | 2 +- .../WindowsAsynchronousFileChannelImpl.java | 2 +- ...wsAsynchronousServerSocketChannelImpl.java | 2 +- .../WindowsAsynchronousSocketChannelImpl.java | 2 +- .../sun/nio/ch/WindowsSelectorImpl.java | 2 +- 41 files changed, 55 insertions(+), 89 deletions(-) diff --git a/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java b/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java index b1f71acc4a3..5c82006000c 100644 --- a/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java +++ b/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java @@ -87,6 +87,7 @@ class KQueueArrayWrapper { private int incomingInterruptFD; static { + IOUtil.load(); initStructSizes(); String datamodel = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("sun.arch.data.model") diff --git a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java index 847c89bdcce..f2340e62ca4 100644 --- a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java +++ b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java @@ -246,9 +246,4 @@ class KQueueSelectorImpl } return this; } - - - static { - Util.load(); - } } diff --git a/jdk/src/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java b/jdk/src/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java index 264b200dee4..22e005df969 100644 --- a/jdk/src/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java @@ -193,9 +193,4 @@ abstract class AbstractPollSelectorImpl if (!selch.isOpen() && !selch.isRegistered()) ((SelChImpl)selch).kill(); } - - static { - Util.load(); - } - } diff --git a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index b99750c4c37..2cda6fa1527 100644 --- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -1138,7 +1138,7 @@ class DatagramChannelImpl throws IOException; static { - Util.load(); + IOUtil.load(); initIDs(); } diff --git a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java index ac9be90f210..b464ecc854a 100644 --- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java @@ -1162,7 +1162,7 @@ public class FileChannelImpl private static native long initIDs(); static { - Util.load(); + IOUtil.load(); allocationGranularity = initIDs(); } diff --git a/jdk/src/share/classes/sun/nio/ch/IOUtil.java b/jdk/src/share/classes/sun/nio/ch/IOUtil.java index 6f45da73d10..ba5449eac70 100644 --- a/jdk/src/share/classes/sun/nio/ch/IOUtil.java +++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java @@ -347,9 +347,23 @@ public class IOUtil { static native void initIDs(); + /** + * Used to trigger loading of native libraries + */ + public static void load() { } + static { - // Note that IOUtil.initIDs is called from within Util.load. - Util.load(); + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + System.loadLibrary("net"); + System.loadLibrary("nio"); + return null; + } + }); + + initIDs(); + IOV_MAX = iovMax(); } diff --git a/jdk/src/share/classes/sun/nio/ch/Net.java b/jdk/src/share/classes/sun/nio/ch/Net.java index 2b68f963ff5..2e2640290c6 100644 --- a/jdk/src/share/classes/sun/nio/ch/Net.java +++ b/jdk/src/share/classes/sun/nio/ch/Net.java @@ -582,7 +582,7 @@ public class Net { private static native void initIDs(); static { - Util.load(); + IOUtil.load(); initIDs(); } diff --git a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index 3b3969cc158..8429442356a 100644 --- a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -416,7 +416,7 @@ class ServerSocketChannelImpl private static native void initIDs(); static { - Util.load(); + IOUtil.load(); initIDs(); nd = new SocketDispatcher(); } diff --git a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java index 6959c17780d..806168392e9 100644 --- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -1024,7 +1024,7 @@ class SocketChannelImpl throws IOException; static { - Util.load(); + IOUtil.load(); nd = new SocketDispatcher(); } diff --git a/jdk/src/share/classes/sun/nio/ch/Util.java b/jdk/src/share/classes/sun/nio/ch/Util.java index 1904ca58824..772f1492a47 100644 --- a/jdk/src/share/classes/sun/nio/ch/Util.java +++ b/jdk/src/share/classes/sun/nio/ch/Util.java @@ -401,30 +401,4 @@ public class Util { return bugLevel.equals(bl); } - - - // -- Initialization -- - - private static boolean loaded = false; - - public static void load() { - synchronized (Util.class) { - if (loaded) - return; - loaded = true; - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Void run() { - System.loadLibrary("net"); - System.loadLibrary("nio"); - return null; - } - }); - - // IOUtil must be initialized; Its native methods are called from - // other places in native nio code so they must be set up. - IOUtil.initIDs(); - } - } - } diff --git a/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java b/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java index 64d4c313a06..079529e5bb4 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java +++ b/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java @@ -36,7 +36,7 @@ import java.net.*; class DatagramDispatcher extends NativeDispatcher { static { - Util.load(); + IOUtil.load(); } int read(FileDescriptor fd, long address, int len) throws IOException { diff --git a/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java b/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java index 3151b227b8b..df30e2924f2 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java +++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java @@ -316,4 +316,8 @@ class DevPollArrayWrapper { private native int poll0(long pollAddress, int numfds, long timeout, int wfd); private static native void interrupt(int fd); + + static { + IOUtil.load(); + } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java index e151051ecea..b0d6a33cbc4 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java @@ -196,9 +196,4 @@ class DevPollSelectorImpl } return this; } - - static { - Util.load(); - } - } diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPoll.java b/jdk/src/solaris/classes/sun/nio/ch/EPoll.java index 3300f962ae0..f0a8d7e3fd9 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/EPoll.java +++ b/jdk/src/solaris/classes/sun/nio/ch/EPoll.java @@ -113,6 +113,6 @@ class EPoll { throws IOException; static { - Util.load(); + IOUtil.load(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java index 3b59a06ac03..a73d3c2dff1 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java @@ -318,6 +318,7 @@ class EPollArrayWrapper { } static { + IOUtil.load(); init(); } diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java b/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java index 6b496ca287a..17cd171bc80 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java @@ -318,6 +318,6 @@ final class EPollPort private static native void close0(int fd); static { - Util.load(); + IOUtil.load(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java index c8bdab4c7be..49f67a8b3dc 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java @@ -196,8 +196,4 @@ class EPollSelectorImpl } return this; } - - static { - Util.load(); - } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java b/jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java index 37c1d5b9098..145824bf0bc 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java @@ -31,7 +31,7 @@ class FileDispatcherImpl extends FileDispatcher { static { - Util.load(); + IOUtil.load(); init(); } diff --git a/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java b/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java index 2917ba9c74a..ac9b8c5f05b 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java +++ b/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java @@ -235,6 +235,6 @@ class InheritedChannel { private static native int peerPort0(int fd); static { - Util.load(); + IOUtil.load(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/KQueue.java b/jdk/src/solaris/classes/sun/nio/ch/KQueue.java index e3466e3d7fe..f8796c8d470 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/KQueue.java +++ b/jdk/src/solaris/classes/sun/nio/ch/KQueue.java @@ -115,6 +115,6 @@ class KQueue { throws IOException; static { - Util.load(); + IOUtil.load(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/KQueuePort.java b/jdk/src/solaris/classes/sun/nio/ch/KQueuePort.java index cd16e2e2cca..c323f076fb2 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/KQueuePort.java +++ b/jdk/src/solaris/classes/sun/nio/ch/KQueuePort.java @@ -326,6 +326,6 @@ final class KQueuePort private static native void close0(int fd); static { - Util.load(); + IOUtil.load(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/NativeThread.java b/jdk/src/solaris/classes/sun/nio/ch/NativeThread.java index 7a7e155c4b9..6e1885e0ec8 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/NativeThread.java +++ b/jdk/src/solaris/classes/sun/nio/ch/NativeThread.java @@ -54,7 +54,7 @@ public class NativeThread { private static native void init(); static { - Util.load(); + IOUtil.load(); init(); } diff --git a/jdk/src/solaris/classes/sun/nio/ch/PollArrayWrapper.java b/jdk/src/solaris/classes/sun/nio/ch/PollArrayWrapper.java index bf063c70cfd..3a57bfc4ba2 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/PollArrayWrapper.java +++ b/jdk/src/solaris/classes/sun/nio/ch/PollArrayWrapper.java @@ -126,4 +126,7 @@ public class PollArrayWrapper extends AbstractPollArrayWrapper { private static native void interrupt(int fd); + static { + IOUtil.load(); + } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java index d388dd47fd8..a0645221ed0 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java @@ -37,7 +37,7 @@ class SinkChannelImpl { // Used to make native read and write calls - private static NativeDispatcher nd; + private static final NativeDispatcher nd = new FileDispatcherImpl(); // The file descriptor associated with this channel FileDescriptor fd; @@ -206,10 +206,4 @@ class SinkChannelImpl throw new IndexOutOfBoundsException(); return write(Util.subsequence(srcs, offset, length)); } - - static { - Util.load(); - nd = new FileDispatcherImpl(); - } - } diff --git a/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java b/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java index d5a74c10931..1ff20373ad5 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java @@ -260,6 +260,6 @@ class SolarisEventPort static { - Util.load(); + IOUtil.load(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java index cc374127e97..d632b74259f 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java @@ -37,7 +37,7 @@ class SourceChannelImpl { // Used to make native read and write calls - private static NativeDispatcher nd; + private static final NativeDispatcher nd = new FileDispatcherImpl(); // The file descriptor associated with this channel FileDescriptor fd; @@ -206,10 +206,4 @@ class SourceChannelImpl } } } - - static { - Util.load(); - nd = new FileDispatcherImpl(); - } - } diff --git a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java index 3b431e77b01..752b70ee4f0 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java @@ -345,7 +345,7 @@ class UnixAsynchronousServerSocketChannelImpl throws IOException; static { - Util.load(); + IOUtil.load(); initIDs(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java index 8b74488f1ac..c718057f060 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java @@ -748,6 +748,6 @@ class UnixAsynchronousSocketChannelImpl private static native void checkConnect(int fdVal) throws IOException; static { - Util.load(); + IOUtil.load(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java index f71345c84c3..73c96cfc22b 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java @@ -1106,7 +1106,7 @@ public class SctpChannelImpl extends SctpChannel boolean ready) throws IOException; static { - Util.load(); /* loads nio & net native libraries */ + IOUtil.load(); /* loads nio & net native libraries */ java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { diff --git a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java index 84552ba042d..424c1d1642d 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java @@ -995,7 +995,7 @@ public class SctpMultiChannelImpl extends SctpMultiChannel } static { - Util.load(); /* loads nio & net native libraries */ + IOUtil.load(); /* loads nio & net native libraries */ java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { diff --git a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpServerChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpServerChannelImpl.java index 900d7ab53c0..d22af25f1d1 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpServerChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpServerChannelImpl.java @@ -426,7 +426,7 @@ public class SctpServerChannelImpl extends SctpServerChannel FileDescriptor newfd, InetSocketAddress[] isaa) throws IOException; static { - Util.load(); // loads nio & net native libraries + IOUtil.load(); // loads nio & net native libraries java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { diff --git a/jdk/src/windows/classes/sun/nio/ch/DatagramDispatcher.java b/jdk/src/windows/classes/sun/nio/ch/DatagramDispatcher.java index 7cf2f094293..fc658b7eb74 100644 --- a/jdk/src/windows/classes/sun/nio/ch/DatagramDispatcher.java +++ b/jdk/src/windows/classes/sun/nio/ch/DatagramDispatcher.java @@ -36,7 +36,7 @@ import java.net.*; class DatagramDispatcher extends NativeDispatcher { static { - Util.load(); + IOUtil.load(); } int read(FileDescriptor fd, long address, int len) throws IOException { diff --git a/jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java b/jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java index de3c4f9f705..d7126d5c1ae 100644 --- a/jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java @@ -32,7 +32,7 @@ import sun.misc.JavaIOFileDescriptorAccess; class FileDispatcherImpl extends FileDispatcher { static { - Util.load(); + IOUtil.load(); } /** diff --git a/jdk/src/windows/classes/sun/nio/ch/FileKey.java b/jdk/src/windows/classes/sun/nio/ch/FileKey.java index 397ea499316..830cc72a5b5 100644 --- a/jdk/src/windows/classes/sun/nio/ch/FileKey.java +++ b/jdk/src/windows/classes/sun/nio/ch/FileKey.java @@ -73,6 +73,7 @@ public class FileKey { private static native void initIDs(); static { + IOUtil.load(); initIDs(); } } diff --git a/jdk/src/windows/classes/sun/nio/ch/Iocp.java b/jdk/src/windows/classes/sun/nio/ch/Iocp.java index f0b83a1a456..466a08e7ec8 100644 --- a/jdk/src/windows/classes/sun/nio/ch/Iocp.java +++ b/jdk/src/windows/classes/sun/nio/ch/Iocp.java @@ -443,7 +443,7 @@ class Iocp extends AsynchronousChannelGroupImpl { private static native String getErrorMessage(int error); static { - Util.load(); + IOUtil.load(); initIDs(); // thread agnostic I/O on Vista/2008 or newer diff --git a/jdk/src/windows/classes/sun/nio/ch/PipeImpl.java b/jdk/src/windows/classes/sun/nio/ch/PipeImpl.java index 6eb7dce7efd..4a73c610a5f 100644 --- a/jdk/src/windows/classes/sun/nio/ch/PipeImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/PipeImpl.java @@ -56,7 +56,6 @@ class PipeImpl private static final Random rnd; static { - Util.load(); byte[] someBytes = new byte[8]; boolean resultOK = IOUtil.randomBytes(someBytes); if (resultOK) { diff --git a/jdk/src/windows/classes/sun/nio/ch/SocketDispatcher.java b/jdk/src/windows/classes/sun/nio/ch/SocketDispatcher.java index a03d0af93ad..82cfcd56480 100644 --- a/jdk/src/windows/classes/sun/nio/ch/SocketDispatcher.java +++ b/jdk/src/windows/classes/sun/nio/ch/SocketDispatcher.java @@ -36,7 +36,7 @@ class SocketDispatcher extends NativeDispatcher { static { - Util.load(); + IOUtil.load(); } int read(FileDescriptor fd, long address, int len) throws IOException { diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java index b85271e686e..fd3fa538c13 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java @@ -750,6 +750,6 @@ public class WindowsAsynchronousFileChannelImpl private static native void close0(long handle); static { - Util.load(); + IOUtil.load(); } } diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java index 00d6c463176..9a25da92bea 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java @@ -363,7 +363,7 @@ class WindowsAsynchronousServerSocketChannelImpl private static native void closesocket0(long socket) throws IOException; static { - Util.load(); + IOUtil.load(); initIDs(); } } diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java index b76b6828774..124205a65f7 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -919,7 +919,7 @@ class WindowsAsynchronousSocketChannelImpl private static native void closesocket0(long socket) throws IOException; static { - Util.load(); + IOUtil.load(); initIDs(); } } diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java index 1034bb7d82f..bcaaecd9a26 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java @@ -611,6 +611,6 @@ final class WindowsSelectorImpl extends SelectorImpl { } static { - Util.load(); + IOUtil.load(); } } From 54b7d41e6962d34a384be1e3b78e6b50257dbdbd Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Wed, 28 Aug 2013 09:46:55 -0700 Subject: [PATCH 41/44] 8023713: ZipFileSystem crashes on old zip file To handle extra data field copy correctly even the extra data does not follow the spec Reviewed-by: alanb, martin, chegar --- .../java/util/zip/ZipOutputStream.java | 10 +++ jdk/test/java/util/zip/TestExtraTime.java | 63 +++++++++++++------ 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java index 4072fbed52d..3b76ecaab24 100644 --- a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java +++ b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java @@ -663,6 +663,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { while (off + 4 <= len) { int tag = get16(extra, off); int sz = get16(extra, off + 2); + if (sz < 0 || (off + 4 + sz) > len) { + break; + } if (tag == EXTID_EXTT || tag == EXTID_ZIP64) { skipped += (sz + 4); } @@ -684,11 +687,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { while (off + 4 <= len) { int tag = get16(extra, off); int sz = get16(extra, off + 2); + if (sz < 0 || (off + 4 + sz) > len) { + writeBytes(extra, off, len - off); + return; + } if (tag != EXTID_EXTT && tag != EXTID_ZIP64) { writeBytes(extra, off, sz + 4); } off += (sz + 4); } + if (off < len) { + writeBytes(extra, off, len - off); + } } } diff --git a/jdk/test/java/util/zip/TestExtraTime.java b/jdk/test/java/util/zip/TestExtraTime.java index 9923ea693e0..b96c85f7c02 100644 --- a/jdk/test/java/util/zip/TestExtraTime.java +++ b/jdk/test/java/util/zip/TestExtraTime.java @@ -23,7 +23,7 @@ /** * @test - * @bug 4759491 6303183 7012868 8015666 + * @bug 4759491 6303183 7012868 8015666 8023713 * @summary Test ZOS and ZIS timestamp in extra field correctly */ @@ -32,6 +32,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.FileTime; +import java.util.Arrays; import java.util.TimeZone; import java.util.concurrent.TimeUnit; import java.util.zip.ZipEntry; @@ -52,24 +53,26 @@ public class TestExtraTime { FileTime ctime = FileTime.from(time - 300000, TimeUnit.MILLISECONDS); TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai"); - test(mtime, null, null, null); - // ms-dos 1980 epoch problem - test(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null); - // non-default tz - test(mtime, null, null, tz); + for (byte[] extra : new byte[][] { null, new byte[] {1, 2, 3}}) { + test(mtime, null, null, null, extra); + // ms-dos 1980 epoch problem + test(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null, extra); + // non-default tz + test(mtime, null, null, tz, extra); - test(mtime, atime, null, null); - test(mtime, null, ctime, null); - test(mtime, atime, ctime, null); + test(mtime, atime, null, null, extra); + test(mtime, null, ctime, null, extra); + test(mtime, atime, ctime, null, extra); - test(mtime, atime, null, tz); - test(mtime, null, ctime, tz); - test(mtime, atime, ctime, tz); + test(mtime, atime, null, tz, extra); + test(mtime, null, ctime, tz, extra); + test(mtime, atime, ctime, tz, extra); + } } } static void test(FileTime mtime, FileTime atime, FileTime ctime, - TimeZone tz) throws Throwable { + TimeZone tz, byte[] extra) throws Throwable { System.out.printf("--------------------%nTesting: [%s]/[%s]/[%s]%n", mtime, atime, ctime); TimeZone tz0 = TimeZone.getDefault(); @@ -78,8 +81,8 @@ public class TestExtraTime { } ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zos = new ZipOutputStream(baos); - ZipEntry ze = new ZipEntry("TestExtreTime.java"); - + ZipEntry ze = new ZipEntry("TestExtraTime.java"); + ze.setExtra(extra); ze.setLastModifiedTime(mtime); if (atime != null) ze.setLastAccessTime(atime); @@ -87,6 +90,14 @@ public class TestExtraTime { ze.setCreationTime(ctime); zos.putNextEntry(ze); zos.write(new byte[] { 1,2 ,3, 4}); + + // append an extra entry to help check if the length and data + // of the extra field are being correctly written (in previous + // entry). + if (extra != null) { + ze = new ZipEntry("TestExtraEntry"); + zos.putNextEntry(ze); + } zos.close(); if (tz != null) { TimeZone.setDefault(tz0); @@ -96,23 +107,23 @@ public class TestExtraTime { new ByteArrayInputStream(baos.toByteArray())); ze = zis.getNextEntry(); zis.close(); - check(mtime, atime, ctime, ze); + check(mtime, atime, ctime, ze, extra); // ZipFile Path zpath = Paths.get(System.getProperty("test.dir", "."), - "TestExtraTimp.zip"); + "TestExtraTime.zip"); Files.copy(new ByteArrayInputStream(baos.toByteArray()), zpath); ZipFile zf = new ZipFile(zpath.toFile()); - ze = zf.getEntry("TestExtreTime.java"); + ze = zf.getEntry("TestExtraTime.java"); // ZipFile read entry from cen, which does not have a/ctime, // for now. - check(mtime, null, null, ze); + check(mtime, null, null, ze, extra); zf.close(); Files.delete(zpath); } static void check(FileTime mtime, FileTime atime, FileTime ctime, - ZipEntry ze) { + ZipEntry ze, byte[] extra) { /* System.out.printf(" mtime [%tc]: [%tc]/[%tc]%n", mtime.to(TimeUnit.MILLISECONDS), @@ -130,5 +141,17 @@ public class TestExtraTime { ctime.to(TimeUnit.SECONDS) != ze.getCreationTime().to(TimeUnit.SECONDS)) throw new RuntimeException("Timestamp: storing ctime failed!"); + if (extra != null) { + // if extra data exists, the current implementation put it at + // the end of the extra data array (implementation detail) + byte[] extra1 = ze.getExtra(); + if (extra1 == null || extra1.length < extra.length || + !Arrays.equals(Arrays.copyOfRange(extra1, + extra1.length - extra.length, + extra1.length), + extra)) { + throw new RuntimeException("Timestamp: storing extra field failed!"); + } + } } } From 6c9749918354f8814c07f847350a643be8bb2abc Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Wed, 28 Aug 2013 22:11:14 +0200 Subject: [PATCH 42/44] 8023155: Ensure functional consistency across Random, ThreadLocalRandom, SplittableRandom Co-authored-by: Doug Lea Reviewed-by: mduigou --- jdk/src/share/classes/java/util/Random.java | 700 ++++++++++++-- .../util/concurrent/ThreadLocalRandom.java | 879 +++++++++++++++--- .../java/util/Random/RandomStreamTest.java | 27 - jdk/test/java/util/Random/RandomTest.java | 430 +++++++++ .../SplittableRandomTest.java | 53 +- .../ThreadLocalRandomTest.java | 559 +++++++++++ 6 files changed, 2431 insertions(+), 217 deletions(-) create mode 100644 jdk/test/java/util/Random/RandomTest.java create mode 100644 jdk/test/java/util/concurrent/ThreadLocalRandom/ThreadLocalRandomTest.java diff --git a/jdk/src/share/classes/java/util/Random.java b/jdk/src/share/classes/java/util/Random.java index ae2551c0f9b..2c0e0135c72 100644 --- a/jdk/src/share/classes/java/util/Random.java +++ b/jdk/src/share/classes/java/util/Random.java @@ -26,9 +26,13 @@ package java.util; import java.io.*; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.LongStream; +import java.util.stream.StreamSupport; import sun.misc.Unsafe; @@ -85,6 +89,13 @@ class Random implements java.io.Serializable { private static final long addend = 0xBL; private static final long mask = (1L << 48) - 1; + private static final double DOUBLE_UNIT = 1.0 / (1L << 53); + + // IllegalArgumentException messages + static final String BadBound = "bound must be positive"; + static final String BadRange = "bound must be greater than origin"; + static final String BadSize = "size must be non-negative"; + /** * Creates a new random number generator. This constructor sets * the seed of the random number generator to a value very likely @@ -221,6 +232,82 @@ class Random implements java.io.Serializable { bytes[i++] = (byte)rnd; } + /** + * The form of nextLong used by LongStream Spliterators. If + * origin is greater than bound, acts as unbounded form of + * nextLong, else as bounded form. + * + * @param origin the least value, unless greater than bound + * @param bound the upper bound (exclusive), must not equal origin + * @return a pseudorandom value + */ + final long internalNextLong(long origin, long bound) { + long r = nextLong(); + if (origin < bound) { + long n = bound - origin, m = n - 1; + if ((n & m) == 0L) // power of two + r = (r & m) + origin; + else if (n > 0L) { // reject over-represented candidates + for (long u = r >>> 1; // ensure nonnegative + u + m - (r = u % n) < 0L; // rejection check + u = nextLong() >>> 1) // retry + ; + r += origin; + } + else { // range not representable as long + while (r < origin || r >= bound) + r = nextLong(); + } + } + return r; + } + + /** + * The form of nextInt used by IntStream Spliterators. + * For the unbounded case: uses nextInt(). + * For the bounded case with representable range: uses nextInt(int bound) + * For the bounded case with unrepresentable range: uses nextInt() + * + * @param origin the least value, unless greater than bound + * @param bound the upper bound (exclusive), must not equal origin + * @return a pseudorandom value + */ + final int internalNextInt(int origin, int bound) { + if (origin < bound) { + int n = bound - origin; + if (n > 0) { + return nextInt(n) + origin; + } + else { // range not representable as int + int r; + do { + r = nextInt(); + } while (r < origin || r >= bound); + return r; + } + } + else { + return nextInt(); + } + } + + /** + * The form of nextDouble used by DoubleStream Spliterators. + * + * @param origin the least value, unless greater than bound + * @param bound the upper bound (exclusive), must not equal origin + * @return a pseudorandom value + */ + final double internalNextDouble(double origin, double bound) { + double r = nextDouble(); + if (origin < bound) { + r = r * (bound - origin) + origin; + if (r >= bound) // correct for rounding + r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1); + } + return r; + } + /** * Returns the next pseudorandom, uniformly distributed {@code int} * value from this random number generator's sequence. The general @@ -247,23 +334,23 @@ class Random implements java.io.Serializable { * between 0 (inclusive) and the specified value (exclusive), drawn from * this random number generator's sequence. The general contract of * {@code nextInt} is that one {@code int} value in the specified range - * is pseudorandomly generated and returned. All {@code n} possible + * is pseudorandomly generated and returned. All {@code bound} possible * {@code int} values are produced with (approximately) equal - * probability. The method {@code nextInt(int n)} is implemented by + * probability. The method {@code nextInt(int bound)} is implemented by * class {@code Random} as if by: *
 {@code
-     * public int nextInt(int n) {
-     *   if (n <= 0)
-     *     throw new IllegalArgumentException("n must be positive");
+     * public int nextInt(int bound) {
+     *   if (bound <= 0)
+     *     throw new IllegalArgumentException("bound must be positive");
      *
-     *   if ((n & -n) == n)  // i.e., n is a power of 2
-     *     return (int)((n * (long)next(31)) >> 31);
+     *   if ((bound & -bound) == bound)  // i.e., bound is a power of 2
+     *     return (int)((bound * (long)next(31)) >> 31);
      *
      *   int bits, val;
      *   do {
      *       bits = next(31);
-     *       val = bits % n;
-     *   } while (bits - val + (n-1) < 0);
+     *       val = bits % bound;
+     *   } while (bits - val + (bound-1) < 0);
      *   return val;
      * }}
* @@ -289,28 +376,28 @@ class Random implements java.io.Serializable { * greatly increases the length of the sequence of values returned by * successive calls to this method if n is a small power of two. * - * @param n the bound on the random number to be returned. Must be - * positive. + * @param bound the upper bound (exclusive). Must be positive. * @return the next pseudorandom, uniformly distributed {@code int} - * value between {@code 0} (inclusive) and {@code n} (exclusive) + * value between zero (inclusive) and {@code bound} (exclusive) * from this random number generator's sequence - * @throws IllegalArgumentException if n is not positive + * @throws IllegalArgumentException if bound is not positive * @since 1.2 */ + public int nextInt(int bound) { + if (bound <= 0) + throw new IllegalArgumentException(BadBound); - public int nextInt(int n) { - if (n <= 0) - throw new IllegalArgumentException("n must be positive"); - - if ((n & -n) == n) // i.e., n is a power of 2 - return (int)((n * (long)next(31)) >> 31); - - int bits, val; - do { - bits = next(31); - val = bits % n; - } while (bits - val + (n-1) < 0); - return val; + int r = next(31); + int m = bound - 1; + if ((bound & m) == 0) // i.e., bound is a power of 2 + r = (int)((bound * (long)r) >> 31); + else { + for (int u = r; + u - (r = u % bound) + m < 0; + u = next(31)) + ; + } + return r; } /** @@ -442,8 +529,7 @@ class Random implements java.io.Serializable { * @see Math#random */ public double nextDouble() { - return (((long)(next(26)) << 27) + next(27)) - / (double)(1L << 53); + return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT; } private double nextNextGaussian; @@ -513,57 +599,563 @@ class Random implements java.io.Serializable { } } + // stream methods, coded in a way intended to better isolate for + // maintenance purposes the small differences across forms. + /** - * Returns a stream of pseudorandom, uniformly distributed - * {@code integer} values from this random number generator's - * sequence. Values are obtained as needed by calling - * {@link #nextInt()}. + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code int} values. * - * @return an infinite stream of {@code integer} values + *

A pseudorandom {@code int} value is generated as if it's the result of + * calling the method {@link #nextInt()}. + * + * @param streamSize the number of values to generate + * @return a stream of pseudorandom {@code int} values + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + * @since 1.8 + */ + public IntStream ints(long streamSize) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + return StreamSupport.intStream + (new RandomIntsSpliterator + (this, 0L, streamSize, Integer.MAX_VALUE, 0), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code int} + * values. + * + *

A pseudorandom {@code int} value is generated as if it's the result of + * calling the method {@link #nextInt()}. + * + * @implNote This method is implemented to be equivalent to {@code + * ints(Long.MAX_VALUE)}. + * + * @return a stream of pseudorandom {@code int} values * @since 1.8 */ public IntStream ints() { - return IntStream.generate(this::nextInt); + return StreamSupport.intStream + (new RandomIntsSpliterator + (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0), + false); } /** - * Returns a stream of pseudorandom, uniformly distributed - * {@code long} values from this random number generator's - * sequence. Values are obtained as needed by calling - * {@link #nextLong()}. + * Returns a stream producing the given {@code streamSize} number + * of pseudorandom {@code int} values, each conforming to the given + * origin (inclusive) and bound (exclusive). * - * @return an infinite stream of {@code long} values + *

A pseudorandom {@code int} value is generated as if it's the result of + * calling the following method with the origin and bound: + *

 {@code
+     * int nextInt(int origin, int bound) {
+     *   int n = bound - origin;
+     *   if (n > 0) {
+     *     return nextInt(n) + origin;
+     *   }
+     *   else {  // range not representable as int
+     *     int r;
+     *     do {
+     *       r = nextInt();
+     *     } while (r < origin || r >= bound);
+     *     return r;
+     *   }
+     * }}
+ * + * @param streamSize the number of values to generate + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code int} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero, or {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public IntStream ints(long streamSize, int randomNumberOrigin, + int randomNumberBound) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.intStream + (new RandomIntsSpliterator + (this, 0L, streamSize, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * int} values, each conforming to the given origin (inclusive) and bound + * (exclusive). + * + *

A pseudorandom {@code int} value is generated as if it's the result of + * calling the following method with the origin and bound: + *

 {@code
+     * int nextInt(int origin, int bound) {
+     *   int n = bound - origin;
+     *   if (n > 0) {
+     *     return nextInt(n) + origin;
+     *   }
+     *   else {  // range not representable as int
+     *     int r;
+     *     do {
+     *       r = nextInt();
+     *     } while (r < origin || r >= bound);
+     *     return r;
+     *   }
+     * }}
+ * + * @implNote This method is implemented to be equivalent to {@code + * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}. + * + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code int} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public IntStream ints(int randomNumberOrigin, int randomNumberBound) { + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.intStream + (new RandomIntsSpliterator + (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code long} values. + * + *

A pseudorandom {@code long} value is generated as if it's the result + * of calling the method {@link #nextLong()}. + * + * @param streamSize the number of values to generate + * @return a stream of pseudorandom {@code long} values + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + * @since 1.8 + */ + public LongStream longs(long streamSize) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + return StreamSupport.longStream + (new RandomLongsSpliterator + (this, 0L, streamSize, Long.MAX_VALUE, 0L), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code long} + * values. + * + *

A pseudorandom {@code long} value is generated as if it's the result + * of calling the method {@link #nextLong()}. + * + * @implNote This method is implemented to be equivalent to {@code + * longs(Long.MAX_VALUE)}. + * + * @return a stream of pseudorandom {@code long} values * @since 1.8 */ public LongStream longs() { - return LongStream.generate(this::nextLong); + return StreamSupport.longStream + (new RandomLongsSpliterator + (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L), + false); } /** - * Returns a stream of pseudorandom, uniformly distributed - * {@code double} values between {@code 0.0} and {@code 1.0} - * from this random number generator's sequence. Values are - * obtained as needed by calling {@link #nextDouble()}. + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code long}, each conforming to the given origin + * (inclusive) and bound (exclusive). * - * @return an infinite stream of {@code double} values + *

A pseudorandom {@code long} value is generated as if it's the result + * of calling the following method with the origin and bound: + *

 {@code
+     * long nextLong(long origin, long bound) {
+     *   long r = nextLong();
+     *   long n = bound - origin, m = n - 1;
+     *   if ((n & m) == 0L)  // power of two
+     *     r = (r & m) + origin;
+     *   else if (n > 0L) {  // reject over-represented candidates
+     *     for (long u = r >>> 1;            // ensure nonnegative
+     *          u + m - (r = u % n) < 0L;    // rejection check
+     *          u = nextLong() >>> 1) // retry
+     *         ;
+     *     r += origin;
+     *   }
+     *   else {              // range not representable as long
+     *     while (r < origin || r >= bound)
+     *       r = nextLong();
+     *   }
+     *   return r;
+     * }}
+ * + * @param streamSize the number of values to generate + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code long} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero, or {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public LongStream longs(long streamSize, long randomNumberOrigin, + long randomNumberBound) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.longStream + (new RandomLongsSpliterator + (this, 0L, streamSize, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * long} values, each conforming to the given origin (inclusive) and bound + * (exclusive). + * + *

A pseudorandom {@code long} value is generated as if it's the result + * of calling the following method with the origin and bound: + *

 {@code
+     * long nextLong(long origin, long bound) {
+     *   long r = nextLong();
+     *   long n = bound - origin, m = n - 1;
+     *   if ((n & m) == 0L)  // power of two
+     *     r = (r & m) + origin;
+     *   else if (n > 0L) {  // reject over-represented candidates
+     *     for (long u = r >>> 1;            // ensure nonnegative
+     *          u + m - (r = u % n) < 0L;    // rejection check
+     *          u = nextLong() >>> 1) // retry
+     *         ;
+     *     r += origin;
+     *   }
+     *   else {              // range not representable as long
+     *     while (r < origin || r >= bound)
+     *       r = nextLong();
+     *   }
+     *   return r;
+     * }}
+ * + * @implNote This method is implemented to be equivalent to {@code + * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}. + * + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code long} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public LongStream longs(long randomNumberOrigin, long randomNumberBound) { + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.longStream + (new RandomLongsSpliterator + (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code double} values, each between zero + * (inclusive) and one (exclusive). + * + *

A pseudorandom {@code double} value is generated as if it's the result + * of calling the method {@link #nextDouble()}}. + * + * @param streamSize the number of values to generate + * @return a stream of {@code double} values + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + * @since 1.8 + */ + public DoubleStream doubles(long streamSize) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (this, 0L, streamSize, Double.MAX_VALUE, 0.0), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * double} values, each between zero (inclusive) and one + * (exclusive). + * + *

A pseudorandom {@code double} value is generated as if it's the result + * of calling the method {@link #nextDouble()}}. + * + * @implNote This method is implemented to be equivalent to {@code + * doubles(Long.MAX_VALUE)}. + * + * @return a stream of pseudorandom {@code double} values * @since 1.8 */ public DoubleStream doubles() { - return DoubleStream.generate(this::nextDouble); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0), + false); } /** - * Returns a stream of pseudorandom, Gaussian ("normally") - * distributed {@code double} values with mean {@code 0.0} - * and standard deviation {@code 1.0} from this random number - * generator's sequence. Values are obtained as needed by - * calling {@link #nextGaussian()}. + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code double} values, each conforming to the given origin + * (inclusive) and bound (exclusive). * - * @return an infinite stream of {@code double} values + *

A pseudorandom {@code double} value is generated as if it's the result + * of calling the following method with the origin and bound: + *

 {@code
+     * double nextDouble(double origin, double bound) {
+     *   double r = nextDouble();
+     *   r = r * (bound - origin) + origin;
+     *   if (r >= bound) // correct for rounding
+     *     r = Math.nextDown(bound);
+     *   return r;
+     * }}
+ * + * @param streamSize the number of values to generate + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code double} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} * @since 1.8 */ - public DoubleStream gaussians() { - return DoubleStream.generate(this::nextGaussian); + public DoubleStream doubles(long streamSize, double randomNumberOrigin, + double randomNumberBound) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + if (!(randomNumberOrigin < randomNumberBound)) + throw new IllegalArgumentException(BadRange); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (this, 0L, streamSize, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * double} values, each conforming to the given origin (inclusive) and bound + * (exclusive). + * + *

A pseudorandom {@code double} value is generated as if it's the result + * of calling the following method with the origin and bound: + *

 {@code
+     * double nextDouble(double origin, double bound) {
+     *   double r = nextDouble();
+     *   r = r * (bound - origin) + origin;
+     *   if (r >= bound) // correct for rounding
+     *     r = Math.nextDown(bound);
+     *   return r;
+     * }}
+ * + * @implNote This method is implemented to be equivalent to {@code + * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}. + * + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code double} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) { + if (!(randomNumberOrigin < randomNumberBound)) + throw new IllegalArgumentException(BadRange); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Spliterator for int streams. We multiplex the four int + * versions into one class by treating a bound less than origin as + * unbounded, and also by treating "infinite" as equivalent to + * Long.MAX_VALUE. For splits, it uses the standard divide-by-two + * approach. The long and double versions of this class are + * identical except for types. + */ + static final class RandomIntsSpliterator implements Spliterator.OfInt { + final Random rng; + long index; + final long fence; + final int origin; + final int bound; + RandomIntsSpliterator(Random rng, long index, long fence, + int origin, int bound) { + this.rng = rng; this.index = index; this.fence = fence; + this.origin = origin; this.bound = bound; + } + + public RandomIntsSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomIntsSpliterator(rng, i, index = m, origin, bound); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + public boolean tryAdvance(IntConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(rng.internalNextInt(origin, bound)); + index = i + 1; + return true; + } + return false; + } + + public void forEachRemaining(IntConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + index = f; + Random r = rng; + int o = origin, b = bound; + do { + consumer.accept(r.internalNextInt(o, b)); + } while (++i < f); + } + } + } + + /** + * Spliterator for long streams. + */ + static final class RandomLongsSpliterator implements Spliterator.OfLong { + final Random rng; + long index; + final long fence; + final long origin; + final long bound; + RandomLongsSpliterator(Random rng, long index, long fence, + long origin, long bound) { + this.rng = rng; this.index = index; this.fence = fence; + this.origin = origin; this.bound = bound; + } + + public RandomLongsSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomLongsSpliterator(rng, i, index = m, origin, bound); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + public boolean tryAdvance(LongConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(rng.internalNextLong(origin, bound)); + index = i + 1; + return true; + } + return false; + } + + public void forEachRemaining(LongConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + index = f; + Random r = rng; + long o = origin, b = bound; + do { + consumer.accept(r.internalNextLong(o, b)); + } while (++i < f); + } + } + + } + + /** + * Spliterator for double streams. + */ + static final class RandomDoublesSpliterator implements Spliterator.OfDouble { + final Random rng; + long index; + final long fence; + final double origin; + final double bound; + RandomDoublesSpliterator(Random rng, long index, long fence, + double origin, double bound) { + this.rng = rng; this.index = index; this.fence = fence; + this.origin = origin; this.bound = bound; + } + + public RandomDoublesSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomDoublesSpliterator(rng, i, index = m, origin, bound); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + public boolean tryAdvance(DoubleConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(rng.internalNextDouble(origin, bound)); + index = i + 1; + return true; + } + return false; + } + + public void forEachRemaining(DoubleConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + index = f; + Random r = rng; + double o = origin, b = bound; + do { + consumer.accept(r.internalNextDouble(o, b)); + } while (++i < f); + } + } } /** diff --git a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java index 0532d3d4382..297f88cd5a3 100644 --- a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java +++ b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -37,11 +37,16 @@ package java.util.concurrent; import java.io.ObjectStreamField; import java.util.Random; +import java.util.Spliterator; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.LongStream; +import java.util.stream.StreamSupport; /** * A random number generator isolated to the current thread. Like the @@ -64,6 +69,10 @@ import java.util.stream.LongStream; *

This class also provides additional commonly used bounded random * generation methods. * + *

Instances of {@code ThreadLocalRandom} are not cryptographically + * secure. Consider instead using {@link java.security.SecureRandom} + * in security-sensitive applications. + * * @since 1.7 * @author Doug Lea */ @@ -85,28 +94,26 @@ public class ThreadLocalRandom extends Random { * application-level overhead and footprint of most concurrent * programs. * + * Even though this class subclasses java.util.Random, it uses the + * same basic algorithm as java.util.SplittableRandom. (See its + * internal documentation for explanations, which are not repeated + * here.) Because ThreadLocalRandoms are not splittable + * though, we use only a single 64bit gamma. + * * Because this class is in a different package than class Thread, * field access methods use Unsafe to bypass access control rules. - * The base functionality of Random methods is conveniently - * isolated in method next(bits), that just reads and writes the - * Thread field rather than its own field. However, to conform to - * the requirements of the Random superclass constructor, the - * common static ThreadLocalRandom maintains an "initialized" - * field for the sake of rejecting user calls to setSeed while - * still allowing a call from constructor. Note that - * serialization is completely unnecessary because there is only a - * static singleton. But we generate a serial form containing - * "rnd" and "initialized" fields to ensure compatibility across - * versions. + * To conform to the requirements of the Random superclass + * constructor, the common static ThreadLocalRandom maintains an + * "initialized" field for the sake of rejecting user calls to + * setSeed while still allowing a call from constructor. Note + * that serialization is completely unnecessary because there is + * only a static singleton. But we generate a serial form + * containing "rnd" and "initialized" fields to ensure + * compatibility across versions. * - * Per-thread initialization is similar to that in the no-arg - * Random constructor, but we avoid correlation among not only - * initial seeds of those created in different threads, but also - * those created using class Random itself; while at the same time - * not changing any statistical properties. So we use the same - * underlying multiplicative sequence, but start the sequence far - * away from the base version, and then merge (xor) current time - * and per-thread probe bits to generate initial values. + * Implementations of non-core methods are mostly the same as in + * SplittableRandom, that were in part derived from a previous + * version of this class. * * The nextLocalGaussian ThreadLocal supports the very rarely used * nextGaussian method by providing a holder for the second of a @@ -115,24 +122,51 @@ public class ThreadLocalRandom extends Random { * but we provide identical statistical properties. */ - // same constants as Random, but must be redeclared because private - private static final long multiplier = 0x5DEECE66DL; - private static final long addend = 0xBL; - private static final long mask = (1L << 48) - 1; - private static final int PROBE_INCREMENT = 0x61c88647; - - /** Generates the basis for per-thread initial seed values */ - private static final AtomicLong seedGenerator = - new AtomicLong(1269533684904616924L); - /** Generates per-thread initialization/probe field */ private static final AtomicInteger probeGenerator = - new AtomicInteger(0xe80f8647); + new AtomicInteger(); + + /** + * The next seed for default constructors. + */ + private static final AtomicLong seeder = + new AtomicLong(mix64(System.currentTimeMillis()) ^ + mix64(System.nanoTime())); + + /** + * The seed increment + */ + private static final long GAMMA = 0x9e3779b97f4a7c15L; + + /** + * The increment for generating probe values + */ + private static final int PROBE_INCREMENT = 0x9e3779b9; + + /** + * The increment of seeder per new instance + */ + private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL; + + // Constants from SplittableRandom + private static final double DOUBLE_UNIT = 1.0 / (1L << 53); + private static final float FLOAT_UNIT = 1.0f / (1 << 24); /** Rarely-used holder for the second of a pair of Gaussians */ private static final ThreadLocal nextLocalGaussian = new ThreadLocal(); + private static long mix64(long z) { + z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; + z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L; + return z ^ (z >>> 33); + } + + private static int mix32(long z) { + z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; + return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32); + } + /** * Field used only during singleton initialization. * True when constructor completes. @@ -155,16 +189,11 @@ public class ThreadLocalRandom extends Random { * rely on (static) atomic generators to initialize the values. */ static final void localInit() { - int p = probeGenerator.getAndAdd(PROBE_INCREMENT); + int p = probeGenerator.addAndGet(PROBE_INCREMENT); int probe = (p == 0) ? 1 : p; // skip 0 - long current, next; - do { // same sequence as j.u.Random but different initial value - current = seedGenerator.get(); - next = current * 181783497276652981L; - } while (!seedGenerator.compareAndSet(current, next)); - long r = next ^ ((long)probe << 32) ^ System.nanoTime(); + long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT)); Thread t = Thread.currentThread(); - UNSAFE.putLong(t, SEED, r); + UNSAFE.putLong(t, SEED, seed); UNSAFE.putInt(t, PROBE, probe); } @@ -191,124 +220,264 @@ public class ThreadLocalRandom extends Random { throw new UnsupportedOperationException(); } - protected int next(int bits) { + final long nextSeed() { Thread t; long r; // read and update per-thread seed - UNSAFE.putLong - (t = Thread.currentThread(), SEED, - r = (UNSAFE.getLong(t, SEED) * multiplier + addend) & mask); - return (int) (r >>> (48-bits)); + UNSAFE.putLong(t = Thread.currentThread(), SEED, + r = UNSAFE.getLong(t, SEED) + GAMMA); + return r; } - /** - * Returns a pseudorandom, uniformly distributed value between the - * given least value (inclusive) and bound (exclusive). - * - * @param least the least value returned - * @param bound the upper bound (exclusive) - * @throws IllegalArgumentException if least greater than or equal - * to bound - * @return the next value - */ - public int nextInt(int least, int bound) { - if (least >= bound) - throw new IllegalArgumentException(); - return nextInt(bound - least) + least; + // We must define this, but never use it. + protected int next(int bits) { + return (int)(mix64(nextSeed()) >>> (64 - bits)); } + // IllegalArgumentException messages + static final String BadBound = "bound must be positive"; + static final String BadRange = "bound must be greater than origin"; + static final String BadSize = "size must be non-negative"; + /** - * Returns a pseudorandom, uniformly distributed value - * between 0 (inclusive) and the specified value (exclusive). + * The form of nextLong used by LongStream Spliterators. If + * origin is greater than bound, acts as unbounded form of + * nextLong, else as bounded form. * - * @param n the bound on the random number to be returned. Must be - * positive. - * @return the next value - * @throws IllegalArgumentException if n is not positive + * @param origin the least value, unless greater than bound + * @param bound the upper bound (exclusive), must not equal origin + * @return a pseudorandom value */ - public long nextLong(long n) { - if (n <= 0) - throw new IllegalArgumentException("n must be positive"); - // Divide n by two until small enough for nextInt. On each - // iteration (at most 31 of them but usually much less), - // randomly choose both whether to include high bit in result - // (offset) and whether to continue with the lower vs upper - // half (which makes a difference only if odd). - long offset = 0; - while (n >= Integer.MAX_VALUE) { - int bits = next(2); - long half = n >>> 1; - long nextn = ((bits & 2) == 0) ? half : n - half; - if ((bits & 1) == 0) - offset += n - nextn; - n = nextn; + final long internalNextLong(long origin, long bound) { + long r = mix64(nextSeed()); + if (origin < bound) { + long n = bound - origin, m = n - 1; + if ((n & m) == 0L) // power of two + r = (r & m) + origin; + else if (n > 0L) { // reject over-represented candidates + for (long u = r >>> 1; // ensure nonnegative + u + m - (r = u % n) < 0L; // rejection check + u = mix64(nextSeed()) >>> 1) // retry + ; + r += origin; + } + else { // range not representable as long + while (r < origin || r >= bound) + r = mix64(nextSeed()); + } } - return offset + nextInt((int) n); - } - - @Override - public IntStream ints() { - return IntStream.generate(() -> current().nextInt()); - } - - @Override - public LongStream longs() { - return LongStream.generate(() -> current().nextLong()); - } - - @Override - public DoubleStream doubles() { - return DoubleStream.generate(() -> current().nextDouble()); - } - - @Override - public DoubleStream gaussians() { - return DoubleStream.generate(() -> current().nextGaussian()); + return r; } /** - * Returns a pseudorandom, uniformly distributed value between the - * given least value (inclusive) and bound (exclusive). + * The form of nextInt used by IntStream Spliterators. + * Exactly the same as long version, except for types. * - * @param least the least value returned + * @param origin the least value, unless greater than bound + * @param bound the upper bound (exclusive), must not equal origin + * @return a pseudorandom value + */ + final int internalNextInt(int origin, int bound) { + int r = mix32(nextSeed()); + if (origin < bound) { + int n = bound - origin, m = n - 1; + if ((n & m) == 0) + r = (r & m) + origin; + else if (n > 0) { + for (int u = r >>> 1; + u + m - (r = u % n) < 0; + u = mix32(nextSeed()) >>> 1) + ; + r += origin; + } + else { + while (r < origin || r >= bound) + r = mix32(nextSeed()); + } + } + return r; + } + + /** + * The form of nextDouble used by DoubleStream Spliterators. + * + * @param origin the least value, unless greater than bound + * @param bound the upper bound (exclusive), must not equal origin + * @return a pseudorandom value + */ + final double internalNextDouble(double origin, double bound) { + double r = (nextLong() >>> 11) * DOUBLE_UNIT; + if (origin < bound) { + r = r * (bound - origin) + origin; + if (r >= bound) // correct for rounding + r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1); + } + return r; + } + + /** + * Returns a pseudorandom {@code int} value. + * + * @return a pseudorandom {@code int} value + */ + public int nextInt() { + return mix32(nextSeed()); + } + + /** + * Returns a pseudorandom {@code int} value between zero (inclusive) + * and the specified bound (exclusive). + * + * @param bound the upper bound (exclusive). Must be positive. + * @return a pseudorandom {@code int} value between zero + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code bound} is not positive + */ + public int nextInt(int bound) { + if (bound <= 0) + throw new IllegalArgumentException(BadBound); + int r = mix32(nextSeed()); + int m = bound - 1; + if ((bound & m) == 0) // power of two + r &= m; + else { // reject over-represented candidates + for (int u = r >>> 1; + u + m - (r = u % bound) < 0; + u = mix32(nextSeed()) >>> 1) + ; + } + return r; + } + + /** + * Returns a pseudorandom {@code int} value between the specified + * origin (inclusive) and the specified bound (exclusive). + * + * @param origin the least value returned * @param bound the upper bound (exclusive) - * @return the next value - * @throws IllegalArgumentException if least greater than or equal - * to bound + * @return a pseudorandom {@code int} value between the origin + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code origin} is greater than + * or equal to {@code bound} */ - public long nextLong(long least, long bound) { - if (least >= bound) - throw new IllegalArgumentException(); - return nextLong(bound - least) + least; + public int nextInt(int origin, int bound) { + if (origin >= bound) + throw new IllegalArgumentException(BadRange); + return internalNextInt(origin, bound); } /** - * Returns a pseudorandom, uniformly distributed {@code double} value - * between 0 (inclusive) and the specified value (exclusive). + * Returns a pseudorandom {@code long} value. * - * @param n the bound on the random number to be returned. Must be - * positive. - * @return the next value - * @throws IllegalArgumentException if n is not positive + * @return a pseudorandom {@code long} value */ - public double nextDouble(double n) { - if (n <= 0) - throw new IllegalArgumentException("n must be positive"); - return nextDouble() * n; + public long nextLong() { + return mix64(nextSeed()); } /** - * Returns a pseudorandom, uniformly distributed value between the - * given least value (inclusive) and bound (exclusive). + * Returns a pseudorandom {@code long} value between zero (inclusive) + * and the specified bound (exclusive). * - * @param least the least value returned + * @param bound the upper bound (exclusive). Must be positive. + * @return a pseudorandom {@code long} value between zero + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code bound} is not positive + */ + public long nextLong(long bound) { + if (bound <= 0) + throw new IllegalArgumentException(BadBound); + long r = mix64(nextSeed()); + long m = bound - 1; + if ((bound & m) == 0L) // power of two + r &= m; + else { // reject over-represented candidates + for (long u = r >>> 1; + u + m - (r = u % bound) < 0L; + u = mix64(nextSeed()) >>> 1) + ; + } + return r; + } + + /** + * Returns a pseudorandom {@code long} value between the specified + * origin (inclusive) and the specified bound (exclusive). + * + * @param origin the least value returned * @param bound the upper bound (exclusive) - * @return the next value - * @throws IllegalArgumentException if least greater than or equal - * to bound + * @return a pseudorandom {@code long} value between the origin + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code origin} is greater than + * or equal to {@code bound} */ - public double nextDouble(double least, double bound) { - if (least >= bound) - throw new IllegalArgumentException(); - return nextDouble() * (bound - least) + least; + public long nextLong(long origin, long bound) { + if (origin >= bound) + throw new IllegalArgumentException(BadRange); + return internalNextLong(origin, bound); + } + + /** + * Returns a pseudorandom {@code double} value between zero + * (inclusive) and one (exclusive). + * + * @return a pseudorandom {@code double} value between zero + * (inclusive) and one (exclusive) + */ + public double nextDouble() { + return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT; + } + + /** + * Returns a pseudorandom {@code double} value between 0.0 + * (inclusive) and the specified bound (exclusive). + * + * @param bound the upper bound (exclusive). Must be positive. + * @return a pseudorandom {@code double} value between zero + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code bound} is not positive + */ + public double nextDouble(double bound) { + if (!(bound > 0.0)) + throw new IllegalArgumentException(BadBound); + double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound; + return (result < bound) ? result : // correct for rounding + Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1); + } + + /** + * Returns a pseudorandom {@code double} value between the specified + * origin (inclusive) and bound (exclusive). + * + * @param origin the least value returned + * @param bound the upper bound (exclusive) + * @return a pseudorandom {@code double} value between the origin + * (inclusive) and the bound (exclusive) + * @throws IllegalArgumentException if {@code origin} is greater than + * or equal to {@code bound} + */ + public double nextDouble(double origin, double bound) { + if (!(origin < bound)) + throw new IllegalArgumentException(BadRange); + return internalNextDouble(origin, bound); + } + + /** + * Returns a pseudorandom {@code boolean} value. + * + * @return a pseudorandom {@code boolean} value + */ + public boolean nextBoolean() { + return mix32(nextSeed()) < 0; + } + + /** + * Returns a pseudorandom {@code float} value between zero + * (inclusive) and one (exclusive). + * + * @return a pseudorandom {@code float} value between zero + * (inclusive) and one (exclusive) + */ + public float nextFloat() { + return (mix32(nextSeed()) >>> 8) * FLOAT_UNIT; } public double nextGaussian() { @@ -329,6 +498,445 @@ public class ThreadLocalRandom extends Random { return v1 * multiplier; } + // stream methods, coded in a way intended to better isolate for + // maintenance purposes the small differences across forms. + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code int} values. + * + * @param streamSize the number of values to generate + * @return a stream of pseudorandom {@code int} values + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + * @since 1.8 + */ + public IntStream ints(long streamSize) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + return StreamSupport.intStream + (new RandomIntsSpliterator + (0L, streamSize, Integer.MAX_VALUE, 0), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code int} + * values. + * + * @implNote This method is implemented to be equivalent to {@code + * ints(Long.MAX_VALUE)}. + * + * @return a stream of pseudorandom {@code int} values + * @since 1.8 + */ + public IntStream ints() { + return StreamSupport.intStream + (new RandomIntsSpliterator + (0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number + * of pseudorandom {@code int} values, each conforming to the given + * origin (inclusive) and bound (exclusive). + * + * @param streamSize the number of values to generate + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code int} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero, or {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public IntStream ints(long streamSize, int randomNumberOrigin, + int randomNumberBound) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.intStream + (new RandomIntsSpliterator + (0L, streamSize, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * int} values, each conforming to the given origin (inclusive) and bound + * (exclusive). + * + * @implNote This method is implemented to be equivalent to {@code + * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}. + * + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code int} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public IntStream ints(int randomNumberOrigin, int randomNumberBound) { + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.intStream + (new RandomIntsSpliterator + (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code long} values. + * + * @param streamSize the number of values to generate + * @return a stream of pseudorandom {@code long} values + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + * @since 1.8 + */ + public LongStream longs(long streamSize) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + return StreamSupport.longStream + (new RandomLongsSpliterator + (0L, streamSize, Long.MAX_VALUE, 0L), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code long} + * values. + * + * @implNote This method is implemented to be equivalent to {@code + * longs(Long.MAX_VALUE)}. + * + * @return a stream of pseudorandom {@code long} values + * @since 1.8 + */ + public LongStream longs() { + return StreamSupport.longStream + (new RandomLongsSpliterator + (0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code long}, each conforming to the given origin + * (inclusive) and bound (exclusive). + * + * @param streamSize the number of values to generate + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code long} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero, or {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public LongStream longs(long streamSize, long randomNumberOrigin, + long randomNumberBound) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.longStream + (new RandomLongsSpliterator + (0L, streamSize, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * long} values, each conforming to the given origin (inclusive) and bound + * (exclusive). + * + * @implNote This method is implemented to be equivalent to {@code + * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}. + * + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code long} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public LongStream longs(long randomNumberOrigin, long randomNumberBound) { + if (randomNumberOrigin >= randomNumberBound) + throw new IllegalArgumentException(BadRange); + return StreamSupport.longStream + (new RandomLongsSpliterator + (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code double} values, each between zero + * (inclusive) and one (exclusive). + * + * @param streamSize the number of values to generate + * @return a stream of {@code double} values + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + * @since 1.8 + */ + public DoubleStream doubles(long streamSize) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (0L, streamSize, Double.MAX_VALUE, 0.0), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * double} values, each between zero (inclusive) and one + * (exclusive). + * + * @implNote This method is implemented to be equivalent to {@code + * doubles(Long.MAX_VALUE)}. + * + * @return a stream of pseudorandom {@code double} values + * @since 1.8 + */ + public DoubleStream doubles() { + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0), + false); + } + + /** + * Returns a stream producing the given {@code streamSize} number of + * pseudorandom {@code double} values, each conforming to the given origin + * (inclusive) and bound (exclusive). + * + * @param streamSize the number of values to generate + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code double} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code streamSize} is + * less than zero + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public DoubleStream doubles(long streamSize, double randomNumberOrigin, + double randomNumberBound) { + if (streamSize < 0L) + throw new IllegalArgumentException(BadSize); + if (!(randomNumberOrigin < randomNumberBound)) + throw new IllegalArgumentException(BadRange); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (0L, streamSize, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Returns an effectively unlimited stream of pseudorandom {@code + * double} values, each conforming to the given origin (inclusive) and bound + * (exclusive). + * + * @implNote This method is implemented to be equivalent to {@code + * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}. + * + * @param randomNumberOrigin the origin (inclusive) of each random value + * @param randomNumberBound the bound (exclusive) of each random value + * @return a stream of pseudorandom {@code double} values, + * each with the given origin (inclusive) and bound (exclusive) + * @throws IllegalArgumentException if {@code randomNumberOrigin} + * is greater than or equal to {@code randomNumberBound} + * @since 1.8 + */ + public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) { + if (!(randomNumberOrigin < randomNumberBound)) + throw new IllegalArgumentException(BadRange); + return StreamSupport.doubleStream + (new RandomDoublesSpliterator + (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound), + false); + } + + /** + * Spliterator for int streams. We multiplex the four int + * versions into one class by treating a bound less than origin as + * unbounded, and also by treating "infinite" as equivalent to + * Long.MAX_VALUE. For splits, it uses the standard divide-by-two + * approach. The long and double versions of this class are + * identical except for types. + */ + static final class RandomIntsSpliterator implements Spliterator.OfInt { + long index; + final long fence; + final int origin; + final int bound; + RandomIntsSpliterator(long index, long fence, + int origin, int bound) { + this.index = index; this.fence = fence; + this.origin = origin; this.bound = bound; + } + + public RandomIntsSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomIntsSpliterator(i, index = m, origin, bound); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + public boolean tryAdvance(IntConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(ThreadLocalRandom.current().internalNextInt(origin, bound)); + index = i + 1; + return true; + } + return false; + } + + public void forEachRemaining(IntConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + index = f; + int o = origin, b = bound; + ThreadLocalRandom rng = ThreadLocalRandom.current(); + do { + consumer.accept(rng.internalNextInt(o, b)); + } while (++i < f); + } + } + } + + /** + * Spliterator for long streams. + */ + static final class RandomLongsSpliterator implements Spliterator.OfLong { + long index; + final long fence; + final long origin; + final long bound; + RandomLongsSpliterator(long index, long fence, + long origin, long bound) { + this.index = index; this.fence = fence; + this.origin = origin; this.bound = bound; + } + + public RandomLongsSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomLongsSpliterator(i, index = m, origin, bound); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + public boolean tryAdvance(LongConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(ThreadLocalRandom.current().internalNextLong(origin, bound)); + index = i + 1; + return true; + } + return false; + } + + public void forEachRemaining(LongConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + index = f; + long o = origin, b = bound; + ThreadLocalRandom rng = ThreadLocalRandom.current(); + do { + consumer.accept(rng.internalNextLong(o, b)); + } while (++i < f); + } + } + + } + + /** + * Spliterator for double streams. + */ + static final class RandomDoublesSpliterator implements Spliterator.OfDouble { + long index; + final long fence; + final double origin; + final double bound; + RandomDoublesSpliterator(long index, long fence, + double origin, double bound) { + this.index = index; this.fence = fence; + this.origin = origin; this.bound = bound; + } + + public RandomDoublesSpliterator trySplit() { + long i = index, m = (i + fence) >>> 1; + return (m <= i) ? null : + new RandomDoublesSpliterator(i, index = m, origin, bound); + } + + public long estimateSize() { + return fence - index; + } + + public int characteristics() { + return (Spliterator.SIZED | Spliterator.SUBSIZED | + Spliterator.NONNULL | Spliterator.IMMUTABLE); + } + + public boolean tryAdvance(DoubleConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + consumer.accept(ThreadLocalRandom.current().internalNextDouble(origin, bound)); + index = i + 1; + return true; + } + return false; + } + + public void forEachRemaining(DoubleConsumer consumer) { + if (consumer == null) throw new NullPointerException(); + long i = index, f = fence; + if (i < f) { + index = f; + double o = origin, b = bound; + ThreadLocalRandom rng = ThreadLocalRandom.current(); + do { + consumer.accept(rng.internalNextDouble(o, b)); + } while (++i < f); + } + } + } + + // Within-package utilities /* @@ -401,23 +1009,26 @@ public class ThreadLocalRandom extends Random { */ private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("rnd", long.class), - new ObjectStreamField("initialized", boolean.class) + new ObjectStreamField("initialized", boolean.class), }; /** * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it). + * @param s the stream + * @throws java.io.IOException if an I/O error occurs */ - private void writeObject(java.io.ObjectOutputStream out) + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { - java.io.ObjectOutputStream.PutField fields = out.putFields(); + java.io.ObjectOutputStream.PutField fields = s.putFields(); fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED)); fields.put("initialized", true); - out.writeFields(); + s.writeFields(); } /** * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}. + * @return the {@link #current() current} thread's {@code ThreadLocalRandom} */ private Object readResolve() { return current(); diff --git a/jdk/test/java/util/Random/RandomStreamTest.java b/jdk/test/java/util/Random/RandomStreamTest.java index f7b799c484a..e96d57e2639 100644 --- a/jdk/test/java/util/Random/RandomStreamTest.java +++ b/jdk/test/java/util/Random/RandomStreamTest.java @@ -82,13 +82,6 @@ public class RandomStreamTest { assertEquals(destination.size(), count); } - @Test(dataProvider = "suppliers") - public void testRandomGaussianStream(final Random random, final int count) { - final List destination = new ArrayList<>(count); - random.gaussians().limit(count).forEach(destination::add); - assertEquals(destination.size(), count); - } - @Test public void testIntStream() { final long seed = System.currentTimeMillis(); @@ -131,20 +124,6 @@ public class RandomStreamTest { assertEquals(a, b); } - @Test - public void testGaussianStream() { - final long seed = System.currentTimeMillis(); - final Random r1 = new Random(seed); - final double[] a = new double[SIZE]; - for (int i=0; i < SIZE; i++) { - a[i] = r1.nextGaussian(); - } - - final Random r2 = new Random(seed); // same seed - final double[] b = r2.gaussians().limit(SIZE).toArray(); - assertEquals(a, b); - } - @Test public void testThreadLocalIntStream() throws InterruptedException, ExecutionException, TimeoutException { ThreadLocalRandom tlr = ThreadLocalRandom.current(); @@ -163,12 +142,6 @@ public class RandomStreamTest { testRandomResultSupplierConcurrently(() -> tlr.doubles().limit(SIZE).boxed().collect(toList())); } - @Test - public void testThreadLocalGaussianStream() throws InterruptedException, ExecutionException, TimeoutException { - ThreadLocalRandom tlr = ThreadLocalRandom.current(); - testRandomResultSupplierConcurrently(() -> tlr.gaussians().limit(SIZE).boxed().collect(toList())); - } - void testRandomResultSupplierConcurrently(Supplier s) throws InterruptedException, ExecutionException, TimeoutException { // Produce 10 completable future tasks final int tasks = 10; diff --git a/jdk/test/java/util/Random/RandomTest.java b/jdk/test/java/util/Random/RandomTest.java new file mode 100644 index 00000000000..e56ffde1961 --- /dev/null +++ b/jdk/test/java/util/Random/RandomTest.java @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2012, 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. + */ + +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.BiConsumer; + +import static org.testng.Assert.*; + +/** + * @test + * @run testng RandomTest + * @summary test methods on Random + */ +@Test +public class RandomTest { + + // Note: this test was adapted from the 166 TCK ThreadLocalRandomTest test + // and modified to be a TestNG test + + /* + * Testing coverage notes: + * + * We don't test randomness properties, but only that repeated + * calls, up to NCALLS tries, produce at least one different + * result. For bounded versions, we sample various intervals + * across multiples of primes. + */ + + // max numbers of calls to detect getting stuck on one value + static final int NCALLS = 10000; + + // max sampled int bound + static final int MAX_INT_BOUND = (1 << 28); + + // max sampled long bound + static final long MAX_LONG_BOUND = (1L << 42); + + // Number of replications for other checks + static final int REPS = 20; + + /** + * Repeated calls to nextInt produce at least two distinct results + */ + public void testNextInt() { + Random r = new Random(); + int f = r.nextInt(); + int i = 0; + while (i < NCALLS && r.nextInt() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextLong produce at least two distinct results + */ + public void testNextLong() { + Random r = new Random(); + long f = r.nextLong(); + int i = 0; + while (i < NCALLS && r.nextLong() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextBoolean produce at least two distinct results + */ + public void testNextBoolean() { + Random r = new Random(); + boolean f = r.nextBoolean(); + int i = 0; + while (i < NCALLS && r.nextBoolean() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextFloat produce at least two distinct results + */ + public void testNextFloat() { + Random r = new Random(); + float f = r.nextFloat(); + int i = 0; + while (i < NCALLS && r.nextFloat() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextDouble produce at least two distinct results + */ + public void testNextDouble() { + Random r = new Random(); + double f = r.nextDouble(); + int i = 0; + while (i < NCALLS && r.nextDouble() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextGaussian produce at least two distinct results + */ + public void testNextGaussian() { + Random r = new Random(); + double f = r.nextGaussian(); + int i = 0; + while (i < NCALLS && r.nextGaussian() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * nextInt(negative) throws IllegalArgumentException + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNextIntBoundedNeg() { + Random r = new Random(); + int f = r.nextInt(-17); + } + + /** + * nextInt(bound) returns 0 <= value < bound; repeated calls produce at + * least two distinct results + */ + public void testNextIntBounded() { + Random r = new Random(); + // sample bound space across prime number increments + for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) { + int f = r.nextInt(bound); + assertTrue(0 <= f && f < bound); + int i = 0; + int j; + while (i < NCALLS && + (j = r.nextInt(bound)) == f) { + assertTrue(0 <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + + /** + * Invoking sized ints, long, doubles, with negative sizes throws + * IllegalArgumentException + */ + public void testBadStreamSize() { + Random r = new Random(); + executeAndCatchIAE(() -> r.ints(-1L)); + executeAndCatchIAE(() -> r.ints(-1L, 2, 3)); + executeAndCatchIAE(() -> r.longs(-1L)); + executeAndCatchIAE(() -> r.longs(-1L, -1L, 1L)); + executeAndCatchIAE(() -> r.doubles(-1L)); + executeAndCatchIAE(() -> r.doubles(-1L, .5, .6)); + } + + /** + * Invoking bounded ints, long, doubles, with illegal bounds throws + * IllegalArgumentException + */ + public void testBadStreamBounds() { + Random r = new Random(); + executeAndCatchIAE(() -> r.ints(2, 1)); + executeAndCatchIAE(() -> r.ints(10, 42, 42)); + executeAndCatchIAE(() -> r.longs(-1L, -1L)); + executeAndCatchIAE(() -> r.longs(10, 1L, -2L)); + + testDoubleBadOriginBound((o, b) -> r.doubles(10, o, b)); + } + + // An arbitrary finite double value + static final double FINITE = Math.PI; + + void testDoubleBadOriginBound(BiConsumer bi) { + executeAndCatchIAE(() -> bi.accept(17.0, 2.0)); + executeAndCatchIAE(() -> bi.accept(0.0, 0.0)); + executeAndCatchIAE(() -> bi.accept(Double.NaN, FINITE)); + executeAndCatchIAE(() -> bi.accept(FINITE, Double.NaN)); + executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)); + + // Returns NaN +// executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, FINITE)); +// executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); + + executeAndCatchIAE(() -> bi.accept(FINITE, Double.NEGATIVE_INFINITY)); + + // Returns Double.MAX_VALUE +// executeAndCatchIAE(() -> bi.accept(FINITE, Double.POSITIVE_INFINITY)); + + executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY)); + executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, FINITE)); + executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)); + } + + private void executeAndCatchIAE(Runnable r) { + executeAndCatch(IllegalArgumentException.class, r); + } + + private void executeAndCatch(Class expected, Runnable r) { + Exception caught = null; + try { + r.run(); + } + catch (Exception e) { + caught = e; + } + + assertNotNull(caught, + String.format("No Exception was thrown, expected an Exception of %s to be thrown", + expected.getName())); + Assert.assertTrue(expected.isInstance(caught), + String.format("Exception thrown %s not an instance of %s", + caught.getClass().getName(), expected.getName())); + } + + /** + * A sequential sized stream of ints generates the given number of values + */ + public void testIntsCount() { + LongAdder counter = new LongAdder(); + Random r = new Random(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.ints(size).forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + size += 524959; + } + } + + /** + * A sequential sized stream of longs generates the given number of values + */ + public void testLongsCount() { + LongAdder counter = new LongAdder(); + Random r = new Random(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.longs(size).forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + size += 524959; + } + } + + /** + * A sequential sized stream of doubles generates the given number of values + */ + public void testDoublesCount() { + LongAdder counter = new LongAdder(); + Random r = new Random(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.doubles(size).forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + size += 524959; + } + } + + /** + * Each of a sequential sized stream of bounded ints is within bounds + */ + public void testBoundedInts() { + AtomicInteger fails = new AtomicInteger(0); + Random r = new Random(); + long size = 12345L; + for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) { + for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) { + final int lo = least, hi = bound; + r.ints(size, lo, hi). + forEach(x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); + }); + } + } + assertEquals(fails.get(), 0); + } + + /** + * Each of a sequential sized stream of bounded longs is within bounds + */ + public void testBoundedLongs() { + AtomicInteger fails = new AtomicInteger(0); + Random r = new Random(); + long size = 123L; + for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) { + for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { + final long lo = least, hi = bound; + r.longs(size, lo, hi). + forEach(x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); + }); + } + } + assertEquals(fails.get(), 0); + } + + /** + * Each of a sequential sized stream of bounded doubles is within bounds + */ + public void testBoundedDoubles() { + AtomicInteger fails = new AtomicInteger(0); + Random r = new Random(); + long size = 456; + for (double least = 0.00011; least < 1.0e20; least *= 9) { + for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) { + final double lo = least, hi = bound; + r.doubles(size, lo, hi). + forEach(x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); + }); + } + } + assertEquals(fails.get(), 0); + } + + /** + * A parallel unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCount() { + LongAdder counter = new LongAdder(); + Random r = new Random(); + long size = 100; + r.ints().limit(size).parallel().forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A parallel unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCount() { + LongAdder counter = new LongAdder(); + Random r = new Random(); + long size = 100; + r.longs().limit(size).parallel().forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A parallel unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCount() { + LongAdder counter = new LongAdder(); + Random r = new Random(); + long size = 100; + r.doubles().limit(size).parallel().forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A sequential unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCountSeq() { + LongAdder counter = new LongAdder(); + Random r = new Random(); + long size = 100; + r.ints().limit(size).forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A sequential unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCountSeq() { + LongAdder counter = new LongAdder(); + Random r = new Random(); + long size = 100; + r.longs().limit(size).forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A sequential unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCountSeq() { + LongAdder counter = new LongAdder(); + Random r = new Random(); + long size = 100; + r.doubles().limit(size).forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + +} diff --git a/jdk/test/java/util/SplittableRandom/SplittableRandomTest.java b/jdk/test/java/util/SplittableRandom/SplittableRandomTest.java index 23ed242d06d..57e1a3434a3 100644 --- a/jdk/test/java/util/SplittableRandom/SplittableRandomTest.java +++ b/jdk/test/java/util/SplittableRandom/SplittableRandomTest.java @@ -25,8 +25,10 @@ import org.testng.Assert; import org.testng.annotations.Test; import java.util.SplittableRandom; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.LongAdder; +import java.util.function.BiConsumer; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -272,6 +274,53 @@ public class SplittableRandomTest { } } + /** + * nextDouble(bound) throws IllegalArgumentException + */ + public void testNextDoubleBadBound() { + SplittableRandom sr = new SplittableRandom(); + executeAndCatchIAE(() -> sr.nextDouble(0.0)); + executeAndCatchIAE(() -> sr.nextDouble(-0.0)); + executeAndCatchIAE(() -> sr.nextDouble(+0.0)); + executeAndCatchIAE(() -> sr.nextDouble(-1.0)); + executeAndCatchIAE(() -> sr.nextDouble(Double.NaN)); + executeAndCatchIAE(() -> sr.nextDouble(Double.NEGATIVE_INFINITY)); + + // Returns Double.MAX_VALUE +// executeAndCatchIAE(() -> r.nextDouble(Double.POSITIVE_INFINITY)); + } + + /** + * nextDouble(origin, bound) throws IllegalArgumentException + */ + public void testNextDoubleBadOriginBound() { + testDoubleBadOriginBound(new SplittableRandom()::nextDouble); + } + + // An arbitrary finite double value + static final double FINITE = Math.PI; + + void testDoubleBadOriginBound(BiConsumer bi) { + executeAndCatchIAE(() -> bi.accept(17.0, 2.0)); + executeAndCatchIAE(() -> bi.accept(0.0, 0.0)); + executeAndCatchIAE(() -> bi.accept(Double.NaN, FINITE)); + executeAndCatchIAE(() -> bi.accept(FINITE, Double.NaN)); + executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)); + + // Returns NaN +// executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, FINITE)); +// executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); + + executeAndCatchIAE(() -> bi.accept(FINITE, Double.NEGATIVE_INFINITY)); + + // Returns Double.MAX_VALUE +// executeAndCatchIAE(() -> bi.accept(FINITE, Double.POSITIVE_INFINITY)); + + executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY)); + executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, FINITE)); + executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)); + } + /** * nextDouble(least, bound) returns least <= value < bound; * repeated calls produce at least two distinct results @@ -318,8 +367,8 @@ public class SplittableRandomTest { executeAndCatchIAE(() -> r.ints(10, 42, 42)); executeAndCatchIAE(() -> r.longs(-1L, -1L)); executeAndCatchIAE(() -> r.longs(10, 1L, -2L)); - executeAndCatchIAE(() -> r.doubles(0.0, 0.0)); - executeAndCatchIAE(() -> r.doubles(10, .5, .4)); + + testDoubleBadOriginBound((o, b) -> r.doubles(10, o, b)); } private void executeAndCatchIAE(Runnable r) { diff --git a/jdk/test/java/util/concurrent/ThreadLocalRandom/ThreadLocalRandomTest.java b/jdk/test/java/util/concurrent/ThreadLocalRandom/ThreadLocalRandomTest.java new file mode 100644 index 00000000000..e4e91f597bb --- /dev/null +++ b/jdk/test/java/util/concurrent/ThreadLocalRandom/ThreadLocalRandomTest.java @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2012, 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. + */ + +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.BiConsumer; + +import static org.testng.Assert.*; + +/** + * @test + * @run testng ThreadLocalRandomTest + * @summary test methods on ThreadLocalRandom + */ +@Test +public class ThreadLocalRandomTest { + + // Note: this test was copied from the 166 TCK ThreadLocalRandomTest test + // and modified to be a TestNG test + + /* + * Testing coverage notes: + * + * We don't test randomness properties, but only that repeated + * calls, up to NCALLS tries, produce at least one different + * result. For bounded versions, we sample various intervals + * across multiples of primes. + */ + + // max numbers of calls to detect getting stuck on one value + static final int NCALLS = 10000; + + // max sampled int bound + static final int MAX_INT_BOUND = (1 << 28); + + // max sampled long bound + static final long MAX_LONG_BOUND = (1L << 42); + + // Number of replications for other checks + static final int REPS = 20; + + /** + * setSeed throws UnsupportedOperationException + */ + @Test(expectedExceptions = UnsupportedOperationException.class) + public void testSetSeed() { + ThreadLocalRandom.current().setSeed(17); + } + + /** + * Repeated calls to nextInt produce at least two distinct results + */ + public void testNextInt() { + int f = ThreadLocalRandom.current().nextInt(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextLong produce at least two distinct results + */ + public void testNextLong() { + long f = ThreadLocalRandom.current().nextLong(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextBoolean produce at least two distinct results + */ + public void testNextBoolean() { + boolean f = ThreadLocalRandom.current().nextBoolean(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextFloat produce at least two distinct results + */ + public void testNextFloat() { + float f = ThreadLocalRandom.current().nextFloat(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextDouble produce at least two distinct results + */ + public void testNextDouble() { + double f = ThreadLocalRandom.current().nextDouble(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextGaussian produce at least two distinct results + */ + public void testNextGaussian() { + double f = ThreadLocalRandom.current().nextGaussian(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * nextInt(negative) throws IllegalArgumentException + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNextIntBoundedNeg() { + int f = ThreadLocalRandom.current().nextInt(-17); + } + + /** + * nextInt(least >= bound) throws IllegalArgumentException + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNextIntBadBounds() { + int f = ThreadLocalRandom.current().nextInt(17, 2); + } + + /** + * nextInt(bound) returns 0 <= value < bound; repeated calls produce at + * least two distinct results + */ + public void testNextIntBounded() { + // sample bound space across prime number increments + for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) { + int f = ThreadLocalRandom.current().nextInt(bound); + assertTrue(0 <= f && f < bound); + int i = 0; + int j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextInt(bound)) == f) { + assertTrue(0 <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + + /** + * nextInt(least, bound) returns least <= value < bound; repeated calls + * produce at least two distinct results + */ + public void testNextIntBounded2() { + for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) { + for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) { + int f = ThreadLocalRandom.current().nextInt(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + int j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * nextLong(negative) throws IllegalArgumentException + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNextLongBoundedNeg() { + long f = ThreadLocalRandom.current().nextLong(-17); + } + + /** + * nextLong(least >= bound) throws IllegalArgumentException + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNextLongBadBounds() { + long f = ThreadLocalRandom.current().nextLong(17, 2); + } + + /** + * nextLong(bound) returns 0 <= value < bound; repeated calls produce at + * least two distinct results + */ + public void testNextLongBounded() { + for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) { + long f = ThreadLocalRandom.current().nextLong(bound); + assertTrue(0 <= f && f < bound); + int i = 0; + long j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextLong(bound)) == f) { + assertTrue(0 <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + + /** + * nextLong(least, bound) returns least <= value < bound; repeated calls + * produce at least two distinct results + */ + public void testNextLongBounded2() { + for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) { + for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { + long f = ThreadLocalRandom.current().nextLong(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + long j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * nextDouble(bound) throws IllegalArgumentException + */ + public void testNextDoubleBadBound() { + ThreadLocalRandom r = ThreadLocalRandom.current(); + executeAndCatchIAE(() -> r.nextDouble(0.0)); + executeAndCatchIAE(() -> r.nextDouble(-0.0)); + executeAndCatchIAE(() -> r.nextDouble(+0.0)); + executeAndCatchIAE(() -> r.nextDouble(-1.0)); + executeAndCatchIAE(() -> r.nextDouble(Double.NaN)); + executeAndCatchIAE(() -> r.nextDouble(Double.NEGATIVE_INFINITY)); + + // Returns Double.MAX_VALUE +// executeAndCatchIAE(() -> r.nextDouble(Double.POSITIVE_INFINITY)); + } + + /** + * nextDouble(origin, bound) throws IllegalArgumentException + */ + public void testNextDoubleBadOriginBound() { + testDoubleBadOriginBound(ThreadLocalRandom.current()::nextDouble); + } + + // An arbitrary finite double value + static final double FINITE = Math.PI; + + void testDoubleBadOriginBound(BiConsumer bi) { + executeAndCatchIAE(() -> bi.accept(17.0, 2.0)); + executeAndCatchIAE(() -> bi.accept(0.0, 0.0)); + executeAndCatchIAE(() -> bi.accept(Double.NaN, FINITE)); + executeAndCatchIAE(() -> bi.accept(FINITE, Double.NaN)); + executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)); + + // Returns NaN +// executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, FINITE)); +// executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); + + executeAndCatchIAE(() -> bi.accept(FINITE, Double.NEGATIVE_INFINITY)); + + // Returns Double.MAX_VALUE +// executeAndCatchIAE(() -> bi.accept(FINITE, Double.POSITIVE_INFINITY)); + + executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY)); + executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, FINITE)); + executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)); + } + + /** + * nextDouble(least, bound) returns least <= value < bound; repeated calls + * produce at least two distinct results + */ + public void testNextDoubleBounded2() { + for (double least = 0.0001; least < 1.0e20; least *= 8) { + for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) { + double f = ThreadLocalRandom.current().nextDouble(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + double j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * Invoking sized ints, long, doubles, with negative sizes throws + * IllegalArgumentException + */ + public void testBadStreamSize() { + ThreadLocalRandom r = ThreadLocalRandom.current(); + executeAndCatchIAE(() -> r.ints(-1L)); + executeAndCatchIAE(() -> r.ints(-1L, 2, 3)); + executeAndCatchIAE(() -> r.longs(-1L)); + executeAndCatchIAE(() -> r.longs(-1L, -1L, 1L)); + executeAndCatchIAE(() -> r.doubles(-1L)); + executeAndCatchIAE(() -> r.doubles(-1L, .5, .6)); + } + + /** + * Invoking bounded ints, long, doubles, with illegal bounds throws + * IllegalArgumentException + */ + public void testBadStreamBounds() { + ThreadLocalRandom r = ThreadLocalRandom.current(); + executeAndCatchIAE(() -> r.ints(2, 1)); + executeAndCatchIAE(() -> r.ints(10, 42, 42)); + executeAndCatchIAE(() -> r.longs(-1L, -1L)); + executeAndCatchIAE(() -> r.longs(10, 1L, -2L)); + + testDoubleBadOriginBound((o, b) -> r.doubles(10, o, b)); + } + + private void executeAndCatchIAE(Runnable r) { + executeAndCatch(IllegalArgumentException.class, r); + } + + private void executeAndCatch(Class expected, Runnable r) { + Exception caught = null; + try { + r.run(); + } + catch (Exception e) { + caught = e; + } + + assertNotNull(caught, + String.format("No Exception was thrown, expected an Exception of %s to be thrown", + expected.getName())); + Assert.assertTrue(expected.isInstance(caught), + String.format("Exception thrown %s not an instance of %s", + caught.getClass().getName(), expected.getName())); + } + + /** + * A parallel sized stream of ints generates the given number of values + */ + public void testIntsCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.ints(size).parallel().forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + size += 524959; + } + } + + /** + * A parallel sized stream of longs generates the given number of values + */ + public void testLongsCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.longs(size).parallel().forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + size += 524959; + } + } + + /** + * A parallel sized stream of doubles generates the given number of values + */ + public void testDoublesCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.doubles(size).parallel().forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + size += 524959; + } + } + + /** + * Each of a parallel sized stream of bounded ints is within bounds + */ + public void testBoundedInts() { + AtomicInteger fails = new AtomicInteger(0); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 12345L; + for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) { + for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) { + final int lo = least, hi = bound; + r.ints(size, lo, hi).parallel(). + forEach(x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); + }); + } + } + assertEquals(fails.get(), 0); + } + + /** + * Each of a parallel sized stream of bounded longs is within bounds + */ + public void testBoundedLongs() { + AtomicInteger fails = new AtomicInteger(0); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 123L; + for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) { + for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { + final long lo = least, hi = bound; + r.longs(size, lo, hi).parallel(). + forEach(x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); + }); + } + } + assertEquals(fails.get(), 0); + } + + /** + * Each of a parallel sized stream of bounded doubles is within bounds + */ + public void testBoundedDoubles() { + AtomicInteger fails = new AtomicInteger(0); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 456; + for (double least = 0.00011; least < 1.0e20; least *= 9) { + for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) { + final double lo = least, hi = bound; + r.doubles(size, lo, hi).parallel(). + forEach(x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); + }); + } + } + assertEquals(fails.get(), 0); + } + + /** + * A parallel unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.ints().limit(size).parallel().forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A parallel unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.longs().limit(size).parallel().forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A parallel unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.doubles().limit(size).parallel().forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A sequential unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCountSeq() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.ints().limit(size).forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A sequential unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCountSeq() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.longs().limit(size).forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + + /** + * A sequential unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCountSeq() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.doubles().limit(size).forEach(x -> { + counter.increment(); + }); + assertEquals(counter.sum(), size); + } + +} From 932c79bc4c06e324c90ed44cfdb28054816578a9 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Thu, 29 Aug 2013 11:22:44 +0200 Subject: [PATCH 43/44] 8023786: (jdk) setjmp/longjmp changes the process signal mask on OS X Reviewed-by: dholmes --- jdk/src/share/back/SDE.c | 6 ++++++ jdk/src/share/native/common/check_code.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/jdk/src/share/back/SDE.c b/jdk/src/share/back/SDE.c index 34a43b07bff..cf7baa47149 100644 --- a/jdk/src/share/back/SDE.c +++ b/jdk/src/share/back/SDE.c @@ -28,6 +28,12 @@ #include "util.h" #include "SDE.h" +#ifdef __APPLE__ +/* use setjmp/longjmp versions that do not save/restore the signal mask */ +#define setjmp _setjmp +#define longjmp _longjmp +#endif + /** * This SourceDebugExtension code does not * allow concurrent translation - due to caching method. diff --git a/jdk/src/share/native/common/check_code.c b/jdk/src/share/native/common/check_code.c index e1170293f07..6a114f1f02b 100644 --- a/jdk/src/share/native/common/check_code.c +++ b/jdk/src/share/native/common/check_code.c @@ -90,6 +90,12 @@ #include "classfile_constants.h" #include "opcodes.in_out" +#ifdef __APPLE__ +/* use setjmp/longjmp versions that do not save/restore the signal mask */ +#define setjmp _setjmp +#define longjmp _longjmp +#endif + #define MAX_ARRAY_DIMENSIONS 255 /* align byte code */ #ifndef ALIGN_UP From ae3b889b673a99f223d70c822808f0f6e312c9e6 Mon Sep 17 00:00:00 2001 From: Dan Xu Date: Thu, 29 Aug 2013 10:43:46 -0700 Subject: [PATCH 44/44] 4792059: test/java/io/pathNames/GeneralSolaris.java fails on symbolic links Exclude the possible usage of linked files or directories in the test Reviewed-by: alanb --- jdk/test/java/io/pathNames/General.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/jdk/test/java/io/pathNames/General.java b/jdk/test/java/io/pathNames/General.java index a156be92be0..29be50e298b 100644 --- a/jdk/test/java/io/pathNames/General.java +++ b/jdk/test/java/io/pathNames/General.java @@ -28,6 +28,7 @@ import java.io.*; import java.util.*; +import java.nio.file.*; public class General { @@ -57,7 +58,7 @@ public class General { for (int i = 0; i < dl.length; i++) { File f = new File(subdir, dl[i]); File df = new File(dir, f.getPath()); - if (df.exists() && df.isFile()) { + if (Files.isRegularFile(df.toPath(), LinkOption.NOFOLLOW_LINKS)) { return f.getPath(); } } @@ -65,7 +66,7 @@ public class General { File f = (subdir.length() == 0) ? new File(dl[i]) : new File(subdir, dl[i]); File df = new File(dir, f.getPath()); - if (df.exists() && df.isDirectory()) { + if (Files.isDirectory(df.toPath(), LinkOption.NOFOLLOW_LINKS)) { String[] dl2 = df.list(); if (dl2 != null) { String ff = findSomeFile(dir, f.getPath(), dl2); @@ -90,7 +91,7 @@ public class General { } for (int i = 0; i < dl.length; i++) { File f = new File(dir, dl[i]); - if (f.isFile()) { + if (Files.isRegularFile(f.toPath(), LinkOption.NOFOLLOW_LINKS)) { return dl[i]; } } @@ -127,7 +128,7 @@ public class General { } for (int i = 0; i < dl.length; i++) { File f = new File(d, dl[i]); - if (f.isDirectory()) { + if (Files.isDirectory(f.toPath(), LinkOption.NOFOLLOW_LINKS)) { String[] dl2 = f.list(); if (dl2 == null || dl2.length >= 250) { /* Heuristic to avoid scanning huge directories */ @@ -314,7 +315,7 @@ public class General { /* Normal name */ if (f.exists()) { - if (f.isDirectory() && f.list() != null) { + if (Files.isDirectory(f.toPath(), LinkOption.NOFOLLOW_LINKS) && f.list() != null) { if ((n = findSomeFile(ans, create)) != null) checkSlashes(d, create, ans + n, ask + n); if ((n = findSomeDir(ans, create)) != null)